diff --git a/.gitmodules b/.gitmodules index b4cf44ea892..3412a6b589e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -21,3 +21,13 @@ [submodule "vendor/fido2-tests"] path = vendor/fido2-tests url = https://github.com/trezor/fido2-tests.git +[submodule "vendor/cmsis_device_u5"] + path = vendor/cmsis_device_u5 + url = https://github.com/STMicroelectronics/cmsis_device_u5.git +[submodule "vendor/cmsis_5"] + path = vendor/cmsis_5 + url = https://github.com/ARM-software/CMSIS_5.git + +[submodule "vendor/stm32u5xx_hal_driver"] + path = vendor/stm32u5xx_hal_driver + url = https://github.com/trezor/stm32u5xx_hal_driver.git diff --git a/core/.changelog.d/3370.added b/core/.changelog.d/3370.added new file mode 100644 index 00000000000..20f7c864664 --- /dev/null +++ b/core/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/.changelog.d/3940.added b/core/.changelog.d/3940.added new file mode 100644 index 00000000000..3d19564b262 --- /dev/null +++ b/core/.changelog.d/3940.added @@ -0,0 +1 @@ +[T2T1] Allow SD card hotswap based on production date diff --git a/core/Makefile b/core/Makefile index 168e2d0a22e..f39fa4a686e 100644 --- a/core/Makefile +++ b/core/Makefile @@ -41,21 +41,91 @@ TEST_LANG ?= "en" OPENOCD_INTERFACE ?= stlink # OpenOCD transport default. Alternative: jtag OPENOCD_TRANSPORT ?= hla_swd -OPENOCD = openocd -f interface/$(OPENOCD_INTERFACE).cfg -c "transport select $(OPENOCD_TRANSPORT)" -f target/stm32f4x.cfg -OPENOCD_T1 = openocd -f interface/$(OPENOCD_INTERFACE).cfg -c "transport select $(OPENOCD_TRANSPORT)" -f target/stm32f2x.cfg +ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T R DISC1)) +OPENOCD_TARGET = target/stm32f4x.cfg BOARDLOADER_START = 0x08000000 +BOARDLOADER_END = 0x0800C000 BOOTLOADER_START = 0x08020000 -FIRMWARE_P1_START = 0x08040000 +FIRMWARE_START = 0x08040000 FIRMWARE_P2_START = 0x08120000 PRODTEST_START = 0x08040000 -FIRMWARE_T1_START = 0x08010000 - +STORAGE_1_OFFSET = 0x10000 +STORAGE_2_OFFSET = 0x110000 +STORAGE_SIZE = 0x10000 BOARDLOADER_MAXSIZE = 49152 BOOTLOADER_MAXSIZE = 131072 FIRMWARE_P1_MAXSIZE = 786432 FIRMWARE_P2_MAXSIZE = 917504 FIRMWARE_MAXSIZE = 1703936 +BOARDLOADER_SECTOR_START = 0 +BOARDLOADER_SECTOR_END = 3 +BOOTLOADER_SECTOR_START = 5 +BOOTLOADER_SECTOR_END = 5 +FIRMWARE_SECTOR_START = 6 +FIRMWARE_SECTOR_END = 11 +FIRMWARE_P2_SECTOR_START = 17 +FIRMWARE_P2_SECTOR_END = 23 +STORAGE_1_SECTOR_START = 4 +STORAGE_1_SECTOR_END = 4 +STORAGE_2_SECTOR_START = 16 +STORAGE_2_SECTOR_END = 16 + +else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T3T1)) +OPENOCD_TARGET = target/stm32u5x.cfg +BOARDLOADER_START = 0x0C004000 +BOARDLOADER_END = 0x0C010000 +BOOTLOADER_START = 0x0C010000 +FIRMWARE_START = 0x0C050000 +PRODTEST_START = 0x0C050000 +STORAGE_1_OFFSET = 0x30000 +STORAGE_2_OFFSET = 0x50000 +STORAGE_SIZE = 0x10000 +BOARDLOADER_MAXSIZE = 49152 +BOOTLOADER_MAXSIZE = 131072 +FIRMWARE_MAXSIZE = 1703936 +BOARDLOADER_SECTOR_START = 0x2 +BOARDLOADER_SECTOR_END = 0x7 +BOOTLOADER_SECTOR_START = 0x8 +BOOTLOADER_SECTOR_END = 0x17 +FIRMWARE_SECTOR_START = 0x28 +FIRMWARE_SECTOR_END = 0xF8 +STORAGE_1_SECTOR_START = 0x18 +STORAGE_1_SECTOR_END = 0x1F +STORAGE_2_SECTOR_START = 0x20 +STORAGE_2_SECTOR_END = 0x27 +else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),DISC2)) +OPENOCD_TARGET = target/stm32u5x.cfg +BOARDLOADER_START = 0x0C004000 +BOARDLOADER_END = 0x0C010000 +BOOTLOADER_START = 0x0C010000 +FIRMWARE_START = 0x0C050000 +PRODTEST_START = 0x0C050000 +STORAGE_1_OFFSET = 0x30000 +STORAGE_2_OFFSET = 0x50000 +STORAGE_SIZE = 0x10000 +BOARDLOADER_MAXSIZE = 49152 +BOOTLOADER_MAXSIZE = 131072 +FIRMWARE_MAXSIZE = 3735552 +BOARDLOADER_SECTOR_START = 0x2 +BOARDLOADER_SECTOR_END = 0x7 +BOOTLOADER_SECTOR_START = 0x8 +BOOTLOADER_SECTOR_END = 0x17 +FIRMWARE_SECTOR_START = 0x28 +FIRMWARE_SECTOR_END = 0x1F8 +STORAGE_1_SECTOR_START = 0x18 +STORAGE_1_SECTOR_END = 0x1F +STORAGE_2_SECTOR_START = 0x20 +STORAGE_2_SECTOR_END = 0x27 +else ifeq ($(TREZOR_MODEL), 1) +OPENOCD_TARGET = target/stm32f2x.cfg +FIRMWARE_START = 0x08010000 +else +$(error Unknown TREZOR_MODEL: $(TREZOR_MODEL)) +endif + + +OPENOCD = openocd -f interface/$(OPENOCD_INTERFACE).cfg -c "transport select $(OPENOCD_TRANSPORT)" -f $(OPENOCD_TARGET) CFLAGS += -DSCM_REVISION='\"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')\"' @@ -289,10 +359,12 @@ flash_prodtest: $(PRODTEST_BUILD_DIR)/prodtest.bin ## flash prodtest using OpenO $(OPENOCD) -c "init; reset halt; flash write_image erase $< $(PRODTEST_START); exit" flash_firmware: $(FIRMWARE_BUILD_DIR)/firmware.bin ## flash firmware using OpenOCD - $(OPENOCD) -c "init; reset halt; flash write_image erase $<.p1 $(FIRMWARE_P1_START); flash write_image erase $<.p2 $(FIRMWARE_P2_START); exit" +ifdef FIRMWARE_P2_START + $(OPENOCD) -c "init; reset halt; flash write_image erase $<.p1 $(FIRMWARE_START); flash write_image erase $<.p2 $(FIRMWARE_P2_START); exit" -flash_firmware_t1: $(FIRMWARE_BUILD_DIR)/firmware.bin ## flash T1 core port on T1 using OpenOCD - $(OPENOCD_T1) -c "init; reset halt; flash write_image erase $< $(FIRMWARE_T1_START); exit" +else + $(OPENOCD) -c "init; reset halt; flash write_image erase $< $(FIRMWARE_START); exit" +endif flash_combine: $(PRODTEST_BUILD_DIR)/combined.bin ## flash combined using OpenOCD $(OPENOCD) -c "init; reset halt; flash write_image erase $< $(BOARDLOADER_START); exit" @@ -300,11 +372,22 @@ flash_combine: $(PRODTEST_BUILD_DIR)/combined.bin ## flash combined using OpenOC flash_erase: ## erase all sectors in flash bank 0 $(OPENOCD) -c "init; reset halt; flash info 0; flash erase_sector 0 0 last; flash erase_check 0; exit" +flash_erase_bootloader: ## erase bootloader + $(OPENOCD) -c "init; reset halt; flash info 0; flash erase_sector 0 $(BOOTLOADER_SECTOR_START) $(BOOTLOADER_SECTOR_END); exit" + +flash_erase_firmware: ## erase bootloader +ifdef FIRMWARE_P2_START + $(OPENOCD) -c "init; reset halt; flash info 0; flash erase_sector 0 $(FIRMWARE_SECTOR_START) $(FIRMWARE_SECTOR_END); flash erase_sector 0 $(FIRMWARE_P2_SECTOR_START) $(FIRMWARE_P2_SECTOR_END); exit" + +else + $(OPENOCD) -c "init; reset halt; flash info 0; flash erase_sector 0 $(FIRMWARE_SECTOR_START) $(FIRMWARE_SECTOR_END); exit" +endif + flash_read_storage: ## read storage sectors from flash - $(OPENOCD) -c "init; flash read_bank 0 storage1.data 0x10000 65536; flash read_bank 0 storage2.data 0x110000 65536; exit" + $(OPENOCD) -c "init; reset halt; flash read_bank 0 storage1.data $(STORAGE_1_OFFSET) $(STORAGE_SIZE); flash read_bank 0 storage2.data $(STORAGE_2_OFFSET) $(STORAGE_SIZE); exit" flash_erase_storage: ## erase storage sectors from flash - $(OPENOCD) -c "init; flash erase_sector 0 4 4; flash erase_sector 0 16 16; exit" + $(OPENOCD) -c "init; reset halt; flash erase_sector 0 $(STORAGE_1_SECTOR_START) $(STORAGE_1_SECTOR_END); flash erase_sector 0 $(STORAGE_2_SECTOR_START) $(STORAGE_2_SECTOR_END); exit" flash_bootloader_jlink: $(BOOTLOADER_BUILD_DIR)/bootloader.bin ## flash bootloader using JLink JLinkExe -nogui 1 -commanderscript embed/bootloader/bootloader_flash.jlink @@ -367,7 +450,11 @@ combine: ## combine boardloader + bootloader + prodtest into one combined image $(BOARDLOADER_BUILD_DIR)/boardloader.bin \ $(BOOTLOADER_BUILD_DIR)/bootloader.bin \ $(PRODTEST_BUILD_DIR)/prodtest.bin \ - $(PRODTEST_BUILD_DIR)/combined.bin + $(PRODTEST_BUILD_DIR)/combined.bin \ + $(BOARDLOADER_START) \ + $(BOARDLOADER_END) \ + $(BOOTLOADER_START) \ + $(PRODTEST_START) upload: ## upload firmware using trezorctl trezorctl firmware_update -s -f $(FIRMWARE_BUILD_DIR)/firmware.bin diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader index 1efe8e10587..786c9970af7 100644 --- a/core/SConscript.boardloader +++ b/core/SConscript.boardloader @@ -50,6 +50,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c', 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/sha2.c', + 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -65,18 +66,24 @@ SOURCE_MOD += [ 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', - 'vendor/trezor-storage/flash_common.c', - ] +env = Environment(ENV=os.environ, + CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), + CONSTRAINTS=["limited_util_s"], + CPPDEFINES_IMPLICIT=[] + ) + +FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) + +FILE_SUFFIX= env.get('ENV')['SUFFIX'] +LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] + SOURCE_BOARDLOADER = [ - 'embed/boardloader/startup.s', + f"embed/boardloader/startup_{FILE_SUFFIX}.s", 'embed/boardloader/main.c', ] -env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CONSTRAINTS=["limited_util_s"]) - -FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) env.Replace( CP='cp', @@ -104,7 +111,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/boardloader/memory.ld -Wl,--gc-sections -Wl,-Map=build/boardloader/boardloader.map -Wl,--warn-common -Wl,--print-memory-usage', + LINKFLAGS=f"-T embed/boardloader/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/boardloader/boardloader.map -Wl,--warn-common -Wl,--print-memory-usage", CPPPATH=[ 'embed/boardloader', 'embed/lib', @@ -124,7 +131,7 @@ env.Replace( env.Replace( ALLSOURCES=SOURCE_MOD + SOURCE_BOARDLOADER + SOURCE_HAL, - ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'])) + ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( target='CMakeLists.txt', @@ -161,7 +168,7 @@ program_bin = env.Command( target='boardloader.bin', source=program_elf, action=[ - '$OBJCOPY -O binary $SOURCE $TARGET', + '$OBJCOPY -O binary -j .vector_table -j .text -j .data -j .rodata -j .capabilities -j .sensitive $SOURCE $TARGET', '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 94a32226133..25a6d6c14d0 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -36,11 +36,11 @@ if TREZOR_MODEL in ('R', ): FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperator_Regular_8' FONT_BIG=None -elif TREZOR_MODEL in ('T', 'DISC1'): +elif TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'): FONT_NORMAL='Font_TTHoves_Regular_21' - FONT_DEMIBOLD=None + FONT_DEMIBOLD='Font_TTHoves_Regular_21' FONT_BOLD='Font_TTHoves_Bold_17' - FONT_MONO=None + FONT_MONO='Font_TTHoves_Regular_21' FONT_BIG=None # modtrezorcrypto @@ -71,6 +71,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/sha2.c', + 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -93,7 +94,6 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', ] SOURCE_NANOPB = [ @@ -102,15 +102,6 @@ SOURCE_NANOPB = [ 'vendor/nanopb/pb_encode.c', ] -SOURCE_BOOTLOADER = [ - 'embed/bootloader/startup.s', - 'embed/bootloader/header.S', - 'embed/bootloader/bootui.c', - 'embed/bootloader/main.c', - 'embed/bootloader/messages.c', - 'embed/bootloader/protob/messages.pb.c', -] - # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -118,10 +109,27 @@ tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) -env = Environment(ENV=os.environ, CFLAGS=f"{ARGUMENTS.get('CFLAGS', '')} -DPRODUCTION={int(PRODUCTION)} -DBOOTLOADER_QA={int(BOOTLOADER_QA)}") +env = Environment( + ENV=os.environ, + CFLAGS=f"{ARGUMENTS.get('CFLAGS', '')} -DPRODUCTION={int(PRODUCTION)} -DBOOTLOADER_QA={int(BOOTLOADER_QA)}", + CPPDEFINES_IMPLICIT=[] + ) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FILE_SUFFIX= env.get('ENV')['SUFFIX'] +LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] + +SOURCE_BOOTLOADER = [ + f'embed/bootloader/startup_{FILE_SUFFIX}.s', + 'embed/bootloader/header.S', + 'embed/bootloader/bootui.c', + 'embed/bootloader/main.c', + 'embed/bootloader/messages.c', + 'embed/bootloader/protob/messages.pb.c', +] + + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -148,7 +156,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/bootloader/memory.ld -Wl,--gc-sections -Wl,-Map=build/bootloader/bootloader.map -Wl,--warn-common -Wl,--print-memory-usage', + LINKFLAGS=f'-T embed/bootloader/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/bootloader/bootloader.map -Wl,--warn-common -Wl,--print-memory-usage', CPPPATH=[ 'embed/rust', 'embed/bootloader', @@ -158,7 +166,6 @@ env.Replace( 'embed/models', 'embed/trezorhal', 'embed/extmod/modtrezorui', - 'vendor/micropython/lib/cmsis/inc', 'vendor/nanopb', ] + CPPPATH_MOD + PATH_HAL, CPPDEFINES=[ @@ -179,7 +186,7 @@ env.Replace( env.Replace( ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_HAL, - ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}"])) + ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}"])) cmake_gen = env.Command( target='CMakeLists.txt', @@ -268,7 +275,7 @@ program_bin = env.Command( target='bootloader.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if not PRODUCTION else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci index d730e834932..5ac0d88056f 100644 --- a/core/SConscript.bootloader_ci +++ b/core/SConscript.bootloader_ci @@ -6,7 +6,7 @@ import tools TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) -if TREZOR_MODEL in ('1', 'DISC1'): +if TREZOR_MODEL in ('1', 'DISC1', 'DISC2'): # skip bootloader_ci build env = Environment() def build_bootloader_ci(target,source,env): @@ -34,7 +34,7 @@ if TREZOR_MODEL in ('1', 'R'): FONT_BOLD=None FONT_MONO='Font_PixelOperatorMono_Regular_8' FONT_BIG=None -elif TREZOR_MODEL in ('T', ): +elif TREZOR_MODEL in ('T', 'T3T1'): FONT_NORMAL='Font_Roboto_Regular_20' FONT_DEMIBOLD=None FONT_BOLD=None @@ -66,7 +66,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/sha2.c', - 'vendor/trezor-storage/flash_common.c', + 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -94,16 +94,6 @@ SOURCE_NANOPB = [ 'vendor/nanopb/pb_encode.c', ] -SOURCE_BOOTLOADER = [ - 'embed/bootloader_ci/startup.s', - 'embed/bootloader_ci/header.S', - 'embed/bootloader_ci/bootui.c', - 'embed/bootloader_ci/main.c', - 'embed/bootloader_ci/messages.c', - 'embed/bootloader_ci/protob/messages.pb.c', -] - - # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -111,10 +101,25 @@ tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) -env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0'))) +env = Environment( + ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), + CPPDEFINES_IMPLICIT=[] + ) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FILE_SUFFIX= env.get('ENV')['SUFFIX'] +LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] + +SOURCE_BOOTLOADER = [ + f'embed/bootloader_ci/startup_{FILE_SUFFIX}.s', + 'embed/bootloader_ci/header.S', + 'embed/bootloader_ci/bootui.c', + 'embed/bootloader_ci/main.c', + 'embed/bootloader_ci/messages.c', + 'embed/bootloader_ci/protob/messages.pb.c', +] + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -141,7 +146,7 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/bootloader_ci/memory.ld -Wl,--gc-sections -Wl,-Map=build/bootloader_ci/bootloader.map -Wl,--warn-common', + LINKFLAGS=f'-T embed/bootloader_ci/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/bootloader_ci/bootloader.map -Wl,--warn-common', CPPPATH=[ 'embed/bootloader_ci', 'embed/bootloader_ci/nanopb', @@ -150,7 +155,6 @@ env.Replace( 'embed/models', 'embed/trezorhal', 'embed/extmod/modtrezorui', - 'vendor/micropython/lib/cmsis/inc', 'vendor/nanopb', ] + CPPPATH_MOD + PATH_HAL, CPPDEFINES=[ @@ -171,7 +175,7 @@ env.Replace( env.Replace( ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_HAL, - ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'])) + ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( target='CMakeLists.txt', @@ -210,7 +214,7 @@ program_bin = env.Command( target='bootloader.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index fb6b9aee72f..5ff96facd8d 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -33,7 +33,7 @@ if TREZOR_MODEL in ('1', 'R'): FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperator_Regular_8' FONT_BIG=None -elif TREZOR_MODEL in ('T', ): +elif TREZOR_MODEL in ('T', 'T3T1', 'DISC2'): FONT_NORMAL='Font_TTHoves_Regular_21' FONT_DEMIBOLD=None FONT_BOLD='Font_TTHoves_Bold_17' @@ -91,7 +91,7 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', + 'vendor/trezor-storage/flash_area.c', ] if TREZOR_MODEL in ('1', ): @@ -123,8 +123,11 @@ SOURCE_BOOTLOADER = [ ] SOURCE_TREZORHAL = [ + 'embed/trezorhal/unix/boot_args.c', 'embed/trezorhal/unix/display-unix.c', + 'embed/trezorhal/unix/fault_handlers.c', 'embed/trezorhal/unix/flash.c', + 'embed/trezorhal/unix/flash_otp.c', 'embed/trezorhal/unix/common.c', 'embed/trezorhal/unix/touch/touch.c', 'embed/trezorhal/unix/rng.c', @@ -142,6 +145,8 @@ SOURCE_UNIX = [ 'embed/unix/profile.c', ] + + # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -168,8 +173,12 @@ env.Replace( if TREZOR_MODEL in ('T', 'R'): CPU_MODEL = 'STM32F427xx' +elif TREZOR_MODEL in ('T3T1', ): + CPU_MODEL = 'STM32U585xx' elif TREZOR_MODEL in ('DISC1', ): CPU_MODEL = 'STM32F429xx' +elif TREZOR_MODEL in ('DISC2', ): + CPU_MODEL = 'STM32U5A9xx' elif TREZOR_MODEL in ('1',): CPU_MODEL = 'STM32F405xx' else: @@ -258,7 +267,7 @@ def cargo_build(): else: features = ["model_tt"] - if TREZOR_MODEL in ('T',): + if TREZOR_MODEL in ('T', 'T3T1'): features.append('touch') features.append('backlight') if TREZOR_MODEL in ('R', '1'): diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 0ad54da336e..ebdeb4fbb6c 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -21,7 +21,7 @@ FEATURE_FLAGS = { "SYSTEM_VIEW": False, } -FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga"] +FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"] if DISABLE_OPTIGA and PYOPT == '0': FEATURES_WANTED.remove("optiga") @@ -41,7 +41,7 @@ if TREZOR_MODEL in ('1', 'R'): FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperatorMono_Regular_8' FONT_BIG='Font_Unifont_Regular_16' -elif TREZOR_MODEL in ('T', 'DISC1'): +elif TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'): FONT_NORMAL='Font_TTHoves_Regular_21' FONT_DEMIBOLD='Font_TTHoves_DemiBold_21' FONT_BOLD='Font_TTHoves_Bold_17' @@ -58,7 +58,7 @@ SOURCE_MOD += [ 'vendor/trezor-storage/norcow.c', 'vendor/trezor-storage/storage.c', 'vendor/trezor-storage/storage_utils.c', - 'vendor/trezor-storage/flash_common.c', + 'vendor/trezor-storage/flash_area.c', ] # modtrezorcrypto @@ -197,6 +197,7 @@ SOURCE_MOD += [ 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', + 'embed/lib/translations.c', 'embed/lib/unit_variant.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', @@ -345,16 +346,6 @@ SOURCE_MICROPYTHON_SPEED = [ 'vendor/micropython/py/vm.c', ] -SOURCE_FIRMWARE = [ - 'embed/firmware/bl_check.c', - 'embed/firmware/delay.c', - 'embed/firmware/header.S', - 'embed/firmware/main.c', - 'embed/firmware/mphalport.c', - 'embed/firmware/nlrthumb.c', - 'embed/firmware/startup.S', -] - CPPDEFINES_MOD += ['USE_SVC_SHUTDOWN'] if FEATURE_FLAGS["RDI"]: @@ -385,12 +376,28 @@ tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) SOURCE_QSTR = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED -env = Environment(ENV=os.environ, CFLAGS=f"{ARGUMENTS.get('CFLAGS', '')} -DPRODUCTION={int(PRODUCTION)} -DPYOPT={PYOPT} -DBOOTLOADER_QA={int(BOOTLOADER_QA)} -DBITCOIN_ONLY={BITCOIN_ONLY}") +env = Environment( + ENV=os.environ, + CFLAGS=f"{ARGUMENTS.get('CFLAGS', '')} -DPRODUCTION={int(PRODUCTION)} -DPYOPT={PYOPT} -DBOOTLOADER_QA={int(BOOTLOADER_QA)} -DBITCOIN_ONLY={BITCOIN_ONLY}", + CPPDEFINES_IMPLICIT=[] + ) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FILE_SUFFIX= env.get('ENV')['SUFFIX'] -if TREZOR_MODEL in ('T', 'DISC1'): +SOURCE_FIRMWARE = [ + 'embed/firmware/bl_check.c', + 'embed/firmware/delay.c', + 'embed/firmware/header.S', + 'embed/firmware/main.c', + 'embed/firmware/mphalport.c', + 'embed/firmware/nlrthumb.c', + f'embed/firmware/startup_{FILE_SUFFIX}.S', +] + + +if TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'): UI_LAYOUT = 'UI_LAYOUT_TT' ui_layout_feature = 'model_tt' elif TREZOR_MODEL in ('1', 'R'): @@ -448,7 +455,6 @@ env.Replace( 'embed/trezorhal', 'embed/extmod/modtrezorui', 'vendor/micropython', - 'vendor/micropython/lib/cmsis/inc', ] + CPPPATH_MOD + PATH_HAL, CPPDEFINES=[ 'FIRMWARE', @@ -766,7 +772,7 @@ if FROZEN: env.Replace( ALLSOURCES=source_files, - ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}", f"PYOPT={PYOPT}", f"BITCOIN_ONLY={BITCOIN_ONLY}"])) + ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}", f"PYOPT={PYOPT}", f"BITCOIN_ONLY={BITCOIN_ONLY}"])) cmake_gen = env.Command( @@ -806,7 +812,7 @@ if TREZOR_MODEL not in ('1',): ' --rename-section .data=.vendorheader,alloc,load,readonly,contents' ' $SOURCE $TARGET', )) -if TREZOR_MODEL not in ('DISC1', ): +if TREZOR_MODEL not in ('DISC1', 'DISC2'): tools.embed_binary( obj_program, env, @@ -838,23 +844,30 @@ BINARY_NAME += "-dirty" if tools.get_git_modified() else "" BINARY_NAME += ".bin" -if TREZOR_MODEL in ('T', 'R', 'DISC1'): - action_bin=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data --pad-to 0x08100000 $SOURCE ${TARGET}.p1', - '$OBJCOPY -O binary -j .flash2 $SOURCE ${TARGET}.p2', - '$CAT ${TARGET}.p1 ${TARGET}.p2 > $TARGET', - '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), - '$DD if=$TARGET of=${TARGET}.p1 skip=0 bs=128k count=6', - '$CP $TARGET ' + BINARY_NAME, - ] -elif TREZOR_MODEL in ('1',): +if TREZOR_MODEL in ('1'): action_bin=[ - '$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '../legacy/bootloader/firmware_sign.py -f $TARGET', '$CP $TARGET ' + BINARY_NAME, ] else: - raise ValueError('Unknown Trezor model') + if 'STM32F427xx' in CPPDEFINES_HAL or 'STM32F429xx' in CPPDEFINES_HAL: + action_bin=[ + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive --pad-to 0x08100000 $SOURCE ${TARGET}.p1', + '$OBJCOPY -O binary -j .flash2 $SOURCE ${TARGET}.p2', + '$CAT ${TARGET}.p1 ${TARGET}.p2 > $TARGET', + '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), + '$DD if=$TARGET of=${TARGET}.p1 skip=0 bs=128k count=6', + '$CP $TARGET ' + BINARY_NAME, + ] + elif 'STM32U5A9xx' in CPPDEFINES_HAL or 'STM32U585xx' in CPPDEFINES_HAL: + action_bin=[ + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive $SOURCE ${TARGET}', + '$HEADERTOOL -h $TARGET ' + ('-D' if not PRODUCTION else ''), + '$CP $TARGET ' + BINARY_NAME, + ] + else: + raise Exception("Unknown MCU") program_bin = env.Command( target='firmware.bin', diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index c2f9b9d10aa..bf8b4d18862 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -8,7 +8,7 @@ CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) PRODUCTION = ARGUMENTS.get('PRODUCTION', '0') == '1' BOOTLOADER_DEVEL = ARGUMENTS.get('BOOTLOADER_DEVEL', '0') == '1' -if TREZOR_MODEL in ('DISC1', ): +if TREZOR_MODEL in ('DISC1', 'DISC2'): # skip prodtest build env = Environment() def build_prodtest(target,source,env): @@ -19,7 +19,7 @@ if TREZOR_MODEL in ('DISC1', ): action=build_prodtest) Return() -FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb", "consumption_mask", "optiga"] +FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb", "consumption_mask", "optiga", "haptic"] CCFLAGS_MOD = '' CPPPATH_MOD = [] @@ -38,7 +38,7 @@ if TREZOR_MODEL in ('1', 'R'): FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO=None FONT_BIG=None -elif TREZOR_MODEL in ('T', ): +elif TREZOR_MODEL in ('T', 'T3T1'): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_Roboto_Bold_20' @@ -71,6 +71,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/secp256k1.c', 'vendor/trezor-crypto/sha2.c', 'vendor/trezor-crypto/tls_prf.c', + 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -91,21 +92,8 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', ] -SOURCE_PRODTEST = [ - 'embed/prodtest/startup.s', - 'embed/prodtest/header.S', - 'embed/prodtest/main.c', - 'embed/prodtest/prodtest_common.c', -] - -if TREZOR_MODEL in ('R',): - SOURCE_PRODTEST += [ - 'embed/prodtest/optiga_prodtest.c', - ] - # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) @@ -113,10 +101,29 @@ tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) -env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0'))) +env = Environment( + ENV=os.environ, + CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), + CPPDEFINES_IMPLICIT=[]) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FILE_SUFFIX= env.get('ENV')['SUFFIX'] +LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] + + +SOURCE_PRODTEST = [ + f'embed/prodtest/startup_{FILE_SUFFIX}.s', + 'embed/prodtest/header.S', + 'embed/prodtest/main.c', + 'embed/prodtest/prodtest_common.c', +] + +if 'optiga' in FEATURES_AVAILABLE: + SOURCE_PRODTEST += [ + 'embed/prodtest/optiga_prodtest.c', + ] + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -143,14 +150,13 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/prodtest/memory.ld -Wl,--gc-sections -Wl,-Map=build/prodtest/prodtest.map -Wl,--warn-common', + LINKFLAGS=f'-T embed/prodtest/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/prodtest/prodtest.map -Wl,--warn-common', CPPPATH=[ 'embed/prodtest', 'embed/lib', 'embed/models', 'embed/trezorhal', 'embed/extmod/modtrezorui', - 'vendor/micropython/lib/cmsis/inc', ] + CPPPATH_MOD + PATH_HAL, CPPDEFINES=[ 'TREZOR_PRODTEST', @@ -169,7 +175,7 @@ env.Replace( env.Replace( ALLSOURCES=SOURCE_MOD + SOURCE_PRODTEST + SOURCE_HAL, - ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'])) + ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( target='CMakeLists.txt', @@ -226,7 +232,7 @@ program_bin = env.Command( target='prodtest.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.reflash b/core/SConscript.reflash index 026e82689ac..8b63be81755 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -6,7 +6,7 @@ import tools TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) -if TREZOR_MODEL in ('DISC1', ): +if TREZOR_MODEL in ('DISC1', 'DISC2'): # skip reflash build env = Environment() def build_reflash(target,source,env): @@ -33,7 +33,7 @@ if TREZOR_MODEL in ('1', 'R'): FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO=None FONT_BIG=None -elif TREZOR_MODEL in ('T', ): +elif TREZOR_MODEL in ('T', 'T3T1'): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_Roboto_Bold_20' @@ -65,13 +65,7 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', 'vendor/micropython/lib/uzlib/tinflate.c', - 'vendor/trezor-storage/flash_common.c', -] - -SOURCE_REFLASH = [ - 'embed/reflash/startup.s', - 'embed/reflash/header.S', - 'embed/reflash/main.c', + 'vendor/trezor-storage/flash_area.c', ] # fonts @@ -81,10 +75,24 @@ tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) -env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CONSTRAINTS=["limited_util_s"]) +env = Environment( + ENV=os.environ, + CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), + CONSTRAINTS=["limited_util_s"], + CPPDEFINES_IMPLICIT=[] + ) FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FILE_SUFFIX= env.get('ENV')['SUFFIX'] +LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] + +SOURCE_REFLASH = [ + f'embed/reflash/startup_{FILE_SUFFIX}.s', + 'embed/reflash/header.S', + 'embed/reflash/main.c', +] + env.Replace( CP='cp', AS='arm-none-eabi-as', @@ -111,14 +119,13 @@ env.Replace( '-fstack-protector-all ' + env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, CCFLAGS_QSTR='-DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB', - LINKFLAGS='-T embed/reflash/memory.ld -Wl,--gc-sections -Wl,-Map=build/reflash/reflash.map -Wl,--warn-common', + LINKFLAGS=f'-T embed/reflash/memory_{LINKER_SCRIPT_SUFFIX}.ld -Wl,--gc-sections -Wl,-Map=build/reflash/reflash.map -Wl,--warn-common', CPPPATH=[ 'embed/reflash', 'embed/lib', 'embed/models', 'embed/trezorhal', 'embed/extmod/modtrezorui', - 'vendor/micropython/lib/cmsis/inc', ] + CPPPATH_MOD + PATH_HAL, CPPDEFINES=[ 'TREZOR_MODEL_'+TREZOR_MODEL, @@ -134,7 +141,7 @@ env.Replace( env.Replace( ALLSOURCES=SOURCE_MOD + SOURCE_REFLASH + SOURCE_HAL, - ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'])) + ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( target='CMakeLists.txt', @@ -183,7 +190,7 @@ program_bin = env.Command( target='reflash.bin', source=program_elf, action=[ - '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET', + '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data -j .sensitive $SOURCE $TARGET', '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), '$CP $TARGET ' + BINARY_NAME, ], ) diff --git a/core/SConscript.unix b/core/SConscript.unix index fe74a5865d9..f3d20cd66a7 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -7,10 +7,10 @@ import tools BITCOIN_ONLY = ARGUMENTS.get('BITCOIN_ONLY', '0') EVERYTHING = BITCOIN_ONLY != '1' TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') -DMA2D = TREZOR_MODEL in ('T', ) +DMA2D = TREZOR_MODEL in ('T', 'T3T1') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) -if TREZOR_MODEL in ('DISC1', ): +if TREZOR_MODEL in ('DISC1', 'DISC2'): # skip unix build env = Environment() def build_unix(target,source,env): @@ -42,7 +42,7 @@ if TREZOR_MODEL in ('1', 'R'): FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperatorMono_Regular_8' FONT_BIG='Font_Unifont_Regular_16' -elif TREZOR_MODEL in ('T', ): +elif TREZOR_MODEL in ('T', 'T3T1'): FONT_NORMAL='Font_TTHoves_Regular_21' FONT_DEMIBOLD='Font_TTHoves_DemiBold_21' FONT_BOLD='Font_TTHoves_Bold_17' @@ -59,7 +59,7 @@ SOURCE_MOD += [ 'vendor/trezor-storage/norcow.c', 'vendor/trezor-storage/storage.c', 'vendor/trezor-storage/storage_utils.c', - 'vendor/trezor-storage/flash_common.c', + 'vendor/trezor-storage/flash_area.c', ] # modtrezorcrypto @@ -177,7 +177,7 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]: SOURCE_MOD += [ 'embed/extmod/modtrezorio/modtrezorio.c', ] -if TREZOR_MODEL in ('T',): +if TREZOR_MODEL in ('T', 'T3T1'): SOURCE_MOD += [ 'embed/extmod/modtrezorio/ff.c', 'embed/extmod/modtrezorio/ffunicode.c', @@ -197,6 +197,7 @@ SOURCE_MOD += [ 'embed/lib/fonts/fonts.c', 'embed/lib/image.c', 'embed/lib/terminal.c', + 'embed/lib/translations.c', 'embed/lib/unit_variant.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', @@ -374,10 +375,11 @@ SOURCE_MICROPYTHON = [ ] SOURCE_UNIX = [ - 'embed/trezorhal/unix/translations.c', + 'embed/trezorhal/unix/boot_args.c', 'embed/trezorhal/unix/common.c', 'embed/trezorhal/unix/display-unix.c', 'embed/trezorhal/unix/flash.c', + 'embed/trezorhal/unix/flash_otp.c', 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', 'embed/trezorhal/unix/usb.c', @@ -391,7 +393,7 @@ SOURCE_UNIX = [ 'vendor/micropython/ports/unix/input.c', 'vendor/micropython/ports/unix/unix_mphal.c', ] -if TREZOR_MODEL in ('T', 'R'): +if TREZOR_MODEL in ('T', 'R', 'T3T1'): SOURCE_UNIX += [ 'embed/trezorhal/unix/sbu.c', ] @@ -428,7 +430,7 @@ else: env = Environment(ENV=os.environ, CFLAGS='%s -DPYOPT=%s -DBITCOIN_ONLY=%s %s' % (ARGUMENTS.get('CFLAGS', ''), PYOPT, BITCOIN_ONLY, STATIC)) -if TREZOR_MODEL in ('T',): +if TREZOR_MODEL in ('T', 'T3T1'): UI_LAYOUT = 'UI_LAYOUT_TT' ui_layout_feature = 'model_tt' elif TREZOR_MODEL in ('1', 'R'): @@ -495,8 +497,12 @@ env.Replace( if TREZOR_MODEL in ('T', 'R'): CPU_MODEL = 'STM32F427xx' +elif TREZOR_MODEL in ('T3T1', ): + CPU_MODEL = 'STM32U585xx' elif TREZOR_MODEL in ('DISC1', ): CPU_MODEL = 'STM32F429xx' +elif TREZOR_MODEL in ('DISC2', ): + CPU_MODEL = 'STM32U5A9xx' elif TREZOR_MODEL in ('1',): CPU_MODEL = 'STM32F405xx' else: @@ -806,7 +812,7 @@ def cargo_build(): if DMA2D: features.append('dma2d') - if TREZOR_MODEL in ('T',): + if TREZOR_MODEL in ('T', 'T3T1'): features.append('touch') features.append('sd_card') if TREZOR_MODEL in ('R', '1'): diff --git a/core/embed/boardloader/.changelog.d/3370.added b/core/embed/boardloader/.changelog.d/3370.added new file mode 100644 index 00000000000..20f7c864664 --- /dev/null +++ b/core/embed/boardloader/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index 0e58b085824..ea1a00d9b51 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -24,17 +24,23 @@ #include "common.h" #include "compiler_traits.h" #include "display.h" +#include "fault_handlers.h" #include "flash.h" #include "image.h" #include "model.h" +#include "mpu.h" #include "rng.h" #include "terminal.h" + #ifdef USE_SD_CARD #include "sdcard.h" #endif #ifdef USE_SDRAM #include "sdram.h" #endif +#ifdef USE_HASH_PROCESSOR +#include "hash_processor.h" +#endif #include "lowlevel.h" #include "model.h" @@ -42,6 +48,12 @@ #include "memzero.h" +#ifdef STM32U5 +#include "secret.h" +#include "tamper.h" +#include "trustzone.h" +#endif + const uint8_t BOARDLOADER_KEY_M = 2; const uint8_t BOARDLOADER_KEY_N = 3; static const uint8_t * const BOARDLOADER_KEYS[] = { @@ -54,6 +66,44 @@ static const uint8_t * const BOARDLOADER_KEYS[] = { #endif }; +#ifdef STM32U5 +void check_bootloader_version(uint8_t bld_version) { + const uint8_t *counter_addr = + flash_area_get_address(&SECRET_AREA, SECRET_MONOTONIC_COUNTER_OFFSET, + SECRET_MONOTONIC_COUNTER_LEN); + + ensure((counter_addr != NULL) * sectrue, "counter_addr is NULL"); + + int counter = 0; + + for (int i = 0; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) { + secbool not_cleared = sectrue; + for (int j = 0; j < 16; j++) { + if (counter_addr[i * 16 + j] != 0xFF) { + not_cleared = secfalse; + break; + } + } + + if (not_cleared != sectrue) { + counter++; + } else { + break; + } + } + + ensure((bld_version >= counter) * sectrue, "BOOTLOADER DOWNGRADED"); + + if (bld_version > counter) { + for (int i = 0; i < bld_version; i++) { + uint32_t data[4] = {0}; + secret_write((uint8_t *)data, SECRET_MONOTONIC_COUNTER_OFFSET + i * 16, + 16); + } + } +} +#endif + struct BoardCapabilities capablities __attribute__((section(".capabilities_section"))) = { .header = CAPABILITIES_HEADER, @@ -70,8 +120,7 @@ struct BoardCapabilities capablities .terminator_length = 0}; // we use SRAM as SD card read buffer (because DMA can't access the CCMRAM) -extern uint32_t sram_start[]; -#define sdcard_buf sram_start +BUFFER_SECTION uint32_t sdcard_buf[IMAGE_HEADER_SIZE / sizeof(uint32_t)]; #if defined USE_SD_CARD static uint32_t check_sdcard(void) { @@ -161,11 +210,14 @@ static secbool copy_sdcard(void) { for (int i = 0; i < (IMAGE_HEADER_SIZE + codelen) / SDCARD_BLOCK_SIZE; i++) { ensure(sdcard_read_blocks(sdcard_buf, i, 1), NULL); - for (int j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) { - ensure(flash_area_write_word(&BOOTLOADER_AREA, - i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), - sdcard_buf[j]), - NULL); + for (int j = 0; + j < SDCARD_BLOCK_SIZE / (FLASH_BURST_LENGTH * sizeof(uint32_t)); j++) { + ensure( + flash_area_write_burst( + &BOOTLOADER_AREA, + i * SDCARD_BLOCK_SIZE + j * FLASH_BURST_LENGTH * sizeof(uint32_t), + &sdcard_buf[j * FLASH_BURST_LENGTH]), + NULL); } } @@ -194,12 +246,33 @@ int main(void) { return 2; } +#ifdef STM32U5 + tamper_init(); + + if (sectrue == secret_bhk_locked()) { + delete_secrets(); + NVIC_SystemReset(); + } + + trustzone_init_boardloader(); +#endif + +#ifdef STM32F4 clear_otg_hs_memory(); +#endif + + mpu_config_boardloader(); + + fault_handlers_init(); #ifdef USE_SDRAM sdram_init(); #endif +#ifdef USE_HASH_PROCESSOR + hash_processor_init(); +#endif + display_init(); display_clear(); @@ -225,8 +298,15 @@ int main(void) { ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA), "invalid bootloader hash"); +#ifdef STM32U5 + check_bootloader_version(hdr->monotonic); +#endif + ensure_compatible_settings(); + mpu_config_off(); + + // g_boot_command is preserved on STM32U5 jump_to(BOOTLOADER_START + IMAGE_HEADER_SIZE); return 0; diff --git a/core/embed/boardloader/memory.ld b/core/embed/boardloader/memory_stm32f4.ld similarity index 100% rename from core/embed/boardloader/memory.ld rename to core/embed/boardloader/memory_stm32f4.ld diff --git a/core/embed/boardloader/memory_stm32u58.ld b/core/embed/boardloader/memory_stm32u58.ld new file mode 100644 index 00000000000..8fe61fed3bb --- /dev/null +++ b/core/embed/boardloader/memory_stm32u58.ld @@ -0,0 +1,109 @@ +/* Trezor v2 boardloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C004000, LENGTH = 48K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K + SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +SECTIONS { + .vector_table : ALIGN(512) { + KEEP(*(.vector_table)); + } >FLASH AT>FLASH + + .text : ALIGN(4) { + *(.text*); + . = ALIGN(4); /* make the section size a multiple of the word size */ + } >FLASH AT>FLASH + + .rodata : ALIGN(4) { + *(.rodata*); + . = ALIGN(4); /* make the section size a multiple of the word size */ + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(8); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(8) { + *(.sensitive*); + . = ALIGN(4); + } >SRAM2 AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS + + + /* Hard-coded address for capabilities structure */ + .capabilities 0x0C00FF00 : {KEEP(*(.capabilities_section))} +} diff --git a/core/embed/boardloader/memory_stm32u5a.ld b/core/embed/boardloader/memory_stm32u5a.ld new file mode 100644 index 00000000000..0900bb9e5a4 --- /dev/null +++ b/core/embed/boardloader/memory_stm32u5a.ld @@ -0,0 +1,115 @@ +/* Trezor v2 boardloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C004000, LENGTH = 48K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0K /* 512K on U5G */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +SECTIONS { + .vector_table : ALIGN(512) { + KEEP(*(.vector_table)); + } >FLASH AT>FLASH + + .text : ALIGN(4) { + *(.text*); + . = ALIGN(4); /* make the section size a multiple of the word size */ + } >FLASH AT>FLASH + + .rodata : ALIGN(4) { + *(.rodata*); + . = ALIGN(4); /* make the section size a multiple of the word size */ + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(8); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(8) { + *(.sensitive*); + . = ALIGN(4); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS + + + /* Hard-coded address for capabilities structure */ + .capabilities 0x0C00FF00 : {KEEP(*(.capabilities_section))} +} diff --git a/core/embed/boardloader/startup.s b/core/embed/boardloader/startup_stm32f4.s similarity index 100% rename from core/embed/boardloader/startup.s rename to core/embed/boardloader/startup_stm32f4.s diff --git a/core/embed/boardloader/startup_stm32u5.s b/core/embed/boardloader/startup_stm32u5.s new file mode 100644 index 00000000000..991af48e5ff --- /dev/null +++ b/core/embed/boardloader/startup_stm32u5.s @@ -0,0 +1,107 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #16 // padding + msr MSPLIM, r0 + + bl SystemInit + + // read the first rng data and save it + ldr r0, =0 // r0 - previous value + ldr r1, =0 // r1 - whether to compare the previous value + bl rng_read + + // read the next rng data and make sure it is different than previous + // r0 - value returned from previous call + ldr r1, =1 // r1 - whether to compare the previous value + bl rng_read + mov r4, r0 // save TRNG output in r4 + + // wipe memory to remove any possible vestiges of sensitive data + + +fill_ram: + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + mov r2, r4 // r2 - the word-sized value to be written + bl memset_reg + + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + mov r2, r4 // r2 - the word-sized value to be written + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =sram3_end // r1 - point to byte after the end of SRAM + mov r2, r4 // r2 - the word-sized value to be written + bl memset_reg + + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + mov r2, r4 // r2 - the word-sized value to be written + bl memset_reg + + ldr r0, =sram5_start // r0 - point to beginning of SRAM + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + mov r2, r4 // r2 - the word-sized value to be written + bl memset_reg + + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + mov r2, r4 // r2 - the word-sized value to be written + bl memset_reg + + + // setup environment for subsequent stage of code + + +clear_ram: + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =sram3_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram5_start // r0 - point to beginning of SRAM + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + // copy data in from flash + ldr r0, =data_vma // dst addr + ldr r1, =data_lma // src addr + ldr r2, =data_size // size in bytes + bl memcpy + + // copy sensitive data in from flash + ldr r0, =sensitive_vma // dst addr + ldr r1, =sensitive_lma // src addr + ldr r2, =sensitive_size // size in bytes + bl memcpy + + // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value + bl rng_get + ldr r1, = __stack_chk_guard + str r0, [r1] + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/bootloader/.changelog.d/3370.added b/core/embed/bootloader/.changelog.d/3370.added new file mode 100644 index 00000000000..20f7c864664 --- /dev/null +++ b/core/embed/bootloader/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/bootloader/.changelog.d/3429.changed b/core/embed/bootloader/.changelog.d/3429.changed new file mode 100644 index 00000000000..49b350895ac --- /dev/null +++ b/core/embed/bootloader/.changelog.d/3429.changed @@ -0,0 +1 @@ +Speed-up device boot diff --git a/core/embed/bootloader/boot_internal.h b/core/embed/bootloader/boot_internal.h deleted file mode 100644 index b5890382b38..00000000000 --- a/core/embed/bootloader/boot_internal.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BOOT_INTERNAL_H -#define BOOT_INTERNAL_H - -#include -#include - -// The 'g_boot_command' variable stores the 'command' passed to the -// function 'svc_reboot_to_bootloader()'. It may be one of the -// 'BOOT_COMMAND_xxx' values defined in the enumeration, or it could -// be any other value that should be treated as a non-special action, -// in which case the bootloader should behave as if the device was -// just powered up. The variable is set before the main() is called. -extern boot_command_t g_boot_command; - -// The 'g_boot_args' array stores extra arguments passed -// function 'svc_reboot_to_bootloader()' -extern uint8_t g_boot_args[BOOT_ARGS_SIZE]; - -#endif // BOOT_INTERNAL_H diff --git a/core/embed/bootloader/emulator.c b/core/embed/bootloader/emulator.c index c304d75dc11..f050fde6417 100644 --- a/core/embed/bootloader/emulator.c +++ b/core/embed/bootloader/emulator.c @@ -2,11 +2,12 @@ #include #include TREZOR_BOARD -#include "boot_internal.h" +#include "boot_args.h" #include "bootui.h" #include "common.h" #include "display.h" #include "flash.h" +#include "flash_otp.h" #include "model.h" #include "rust_ui.h" #ifdef USE_OPTIGA @@ -19,16 +20,12 @@ uint8_t *FIRMWARE_START = 0; -// Simulation of a boot command normally grabbed during reset processing -boot_command_t g_boot_command = BOOT_COMMAND_NONE; -// Simulation of a boot args normally sitting at the BOOT_ARGS region -uint8_t g_boot_args[BOOT_ARGS_SIZE]; - void set_core_clock(int) {} int bootloader_main(void); -bool sector_is_empty(const flash_area_t *area) { +// assuming storage is single subarea +bool storage_empty(const flash_area_t *area) { const uint8_t *storage = flash_area_get_address(area, 0, 0); size_t storage_size = flash_area_get_size(area); for (size_t i = 0; i < storage_size; i++) { @@ -54,7 +51,7 @@ void usage(void) { printf(" -h show this help\n"); } -bool load_firmware(const char *filename) { +bool load_firmware(const char *filename, uint8_t *hash) { // read the first 6 kB of firmware file into a buffer FILE *file = fopen(filename, "rb"); if (!file) { @@ -86,7 +83,8 @@ bool load_firmware(const char *filename) { BLAKE2S_CTX ctx; blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); blake2s_Update(&ctx, buffer, vhdr.hdrlen + hdr->hdrlen); - blake2s_Final(&ctx, g_boot_args, BLAKE2S_DIGEST_LENGTH); + blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); + return true; } @@ -114,10 +112,12 @@ __attribute__((noreturn)) void display_error_and_die(const char *message, __attribute__((noreturn)) int main(int argc, char **argv) { flash_init(); + flash_otp_init(); + FIRMWARE_START = (uint8_t *)flash_area_get_address(&FIRMWARE_AREA, 0, 0); // simulate non-empty storage so that we know whether it was erased or not - if (sector_is_empty(&STORAGE_AREAS[0])) { + if (storage_empty(&STORAGE_AREAS[0])) { secbool ret = flash_area_write_word(&STORAGE_AREAS[0], 16, 0x12345678); (void)ret; } @@ -130,7 +130,7 @@ __attribute__((noreturn)) int main(int argc, char **argv) { while ((opt = getopt(argc, argv, "hslec:b:f:")) != -1) { switch (opt) { case 's': - g_boot_command = BOOT_COMMAND_STOP_AND_WAIT; + bootargs_set(BOOT_COMMAND_STOP_AND_WAIT, NULL, 0); break; case 'e': display_error = true; @@ -144,10 +144,11 @@ __attribute__((noreturn)) int main(int argc, char **argv) { bitcoin_only = atoi(optarg); break; case 'f': - g_boot_command = BOOT_COMMAND_INSTALL_UPGRADE; - if (!load_firmware(optarg)) { + uint8_t hash[BLAKE2S_DIGEST_LENGTH]; + if (!load_firmware(optarg, hash)) { exit(1); } + bootargs_set(BOOT_COMMAND_INSTALL_UPGRADE, hash, sizeof(hash)); break; #ifdef USE_OPTIGA case 'l': @@ -197,7 +198,7 @@ void mpu_config_off(void) {} __attribute__((noreturn)) void jump_to(void *addr) { bool storage_is_erased = - sector_is_empty(&STORAGE_AREAS[0]) && sector_is_empty(&STORAGE_AREAS[1]); + storage_empty(&STORAGE_AREAS[0]) && storage_empty(&STORAGE_AREAS[1]); if (storage_is_erased) { printf("STORAGE WAS ERASED\n"); diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index f9fed5cc0fd..ca6924ae80d 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -20,11 +20,15 @@ #include #include -#include "boot_internal.h" +#include "boot_args.h" #include "common.h" #include "display.h" +#include "display_utils.h" +#include "fault_handlers.h" #include "flash.h" +#include "flash_otp.h" #include "image.h" +#include "lowlevel.h" #include "messages.pb.h" #include "random_delays.h" #include "secbool.h" @@ -51,6 +55,10 @@ #ifdef USE_RGB_LED #include "rgb_led.h" #endif +#ifdef USE_HASH_PROCESSOR +#include "hash_processor.h" +#endif + #include "model.h" #include "usb.h" #include "version.h" @@ -77,9 +85,10 @@ typedef enum { RETURN_TO_MENU = 0x55667788, } usb_result_t; -volatile secbool dont_optimize_out_true = sectrue; void failed_jump_to_firmware(void); -volatile void (*firmware_jump_fn)(void) = failed_jump_to_firmware; + +SENSITIVE volatile secbool dont_optimize_out_true = sectrue; +SENSITIVE volatile void (*firmware_jump_fn)(void) = failed_jump_to_firmware; static void usb_init_all(secbool usb21_landing) { usb_dev_info_t dev_info = { @@ -214,7 +223,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, case MessageType_MessageType_GetFeatures: process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr); break; -#ifdef USE_OPTIGA +#if defined USE_OPTIGA && !defined STM32U5 case MessageType_MessageType_UnlockBootloader: response = ui_screen_unlock_bootloader_confirm(); if (INPUT_CANCEL == response) { @@ -258,7 +267,7 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) { // protection against bootloader downgrade -#if PRODUCTION +#if PRODUCTION && !defined STM32U5 static void check_bootloader_version(void) { uint8_t bits[FLASH_OTP_BLOCK_SIZE]; @@ -317,11 +326,32 @@ void real_jump_to_firmware(void) { &FIRMWARE_AREA), "Firmware is corrupted"); +#ifdef STM32U5 + secret_bhk_provision(); + secret_bhk_lock(); +#ifdef USE_OPTIGA + if (sectrue == secret_optiga_present()) { + secret_optiga_backup(); + secret_hide(); + } else { + secret_optiga_hide(); + } +#else + secret_hide(); +#endif +#endif + #ifdef USE_OPTIGA +#ifdef STM32U5 + if ((vhdr.vtrust & VTRUST_SECRET) != 0) { + secret_optiga_hide(); + } +#else if (((vhdr.vtrust & VTRUST_SECRET) != 0) && (sectrue != secret_wiped())) { ui_screen_install_restricted(); trezor_shutdown(); } +#endif #endif // if all VTRUST flags are unset = ultimate trust => skip the procedure @@ -357,6 +387,18 @@ void real_jump_to_firmware(void) { jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); } +#ifdef STM32U5 +__attribute__((noreturn)) void jump_to_fw_through_reset(void) { + display_fade(display_backlight(-1), 0, 200); + + __disable_irq(); + delete_secrets(); + NVIC_SystemReset(); + for (;;) + ; +} +#endif + #ifndef TREZOR_EMULATOR int main(void) { #else @@ -365,7 +407,38 @@ int bootloader_main(void) { secbool stay_in_bootloader = secfalse; random_delays_init(); - // display_init_seq(); + +#if defined TREZOR_MODEL_T + set_core_clock(CLOCK_180_MHZ); +#endif + +#ifdef STM32U5 + if (sectrue != flash_configure_sec_area_ob()) { +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif + + const secbool r = + flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL); + (void)r; + __disable_irq(); + HAL_NVIC_SystemReset(); + } +#endif + +#ifdef USE_HASH_PROCESSOR + hash_processor_init(); +#endif + +#ifdef USE_I2C + i2c_init(); +#endif + +#ifdef USE_TOUCH + touch_power_on(); + touch_init(); +#endif + #ifdef USE_DMA2D dma2d_init(); #endif @@ -376,6 +449,8 @@ int bootloader_main(void) { mpu_config_bootloader(); + fault_handlers_init(); + #ifdef TREZOR_EMULATOR // wait a bit so that the empty lock icon is visible // (on a real device, we are waiting for touch init which takes longer) @@ -428,24 +503,10 @@ int bootloader_main(void) { firmware_present_backup = firmware_present; } -#if defined TREZOR_MODEL_T - set_core_clock(CLOCK_180_MHZ); - display_set_little_endian(); -#endif - -#ifdef USE_I2C - i2c_init(); -#endif - #ifdef USE_OPTIGA optiga_hal_init(); #endif -#ifdef USE_TOUCH - touch_power_on(); - touch_init(); -#endif - #ifdef USE_BUTTON button_init(); #endif @@ -460,11 +521,12 @@ int bootloader_main(void) { unit_variant_init(); -#if PRODUCTION +#if PRODUCTION && !defined STM32U5 + // for STM32U5, this check is moved to boardloader check_bootloader_version(); #endif - switch (g_boot_command) { + switch (bootargs_get_command()) { case BOOT_COMMAND_STOP_AND_WAIT: // firmare requested to stay in bootloader stay_in_bootloader = sectrue; @@ -487,7 +549,8 @@ int bootloader_main(void) { uint32_t touched = 0; #ifdef USE_TOUCH if (firmware_present == sectrue && stay_in_bootloader != sectrue) { - for (int i = 0; i < 100; i++) { + touch_wait_until_ready(); + for (int i = 0; i < 10; i++) { touched = touch_is_detected() | touch_read(); if (touched) { break; @@ -495,7 +558,7 @@ int bootloader_main(void) { #ifdef TREZOR_EMULATOR hal_delay(25); #else - hal_delay(1); + hal_delay_us(1000); #endif } } @@ -529,6 +592,9 @@ int bootloader_main(void) { } else { screen = SCREEN_WELCOME; +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif // erase storage ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), NULL); @@ -583,7 +649,9 @@ int bootloader_main(void) { screen = SCREEN_INTRO; } if (ui_result == 0x11223344) { // reboot +#ifndef STM32U5 ui_screen_boot_empty(true); +#endif continue_to_firmware = firmware_present; continue_to_firmware_backup = firmware_present_backup; } @@ -633,6 +701,10 @@ int bootloader_main(void) { if (continue_to_firmware != continue_to_firmware_backup) { // erase storage if we saw flips randomly flip, most likely due to // glitch + +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), NULL); } @@ -640,7 +712,11 @@ int bootloader_main(void) { (continue_to_firmware == continue_to_firmware_backup), NULL); if (sectrue == continue_to_firmware) { +#ifdef STM32U5 + firmware_jump_fn = jump_to_fw_through_reset; +#else firmware_jump_fn = real_jump_to_firmware; +#endif break; } } @@ -648,13 +724,19 @@ int bootloader_main(void) { ensure(dont_optimize_out_true * (firmware_present == firmware_present_backup), NULL); + +#ifdef STM32U5 + if (sectrue == firmware_present && + firmware_jump_fn != jump_to_fw_through_reset) { + firmware_jump_fn = real_jump_to_firmware; + } +#else if (sectrue == firmware_present) { firmware_jump_fn = real_jump_to_firmware; } +#endif firmware_jump_fn(); return 0; } - -void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } diff --git a/core/embed/bootloader_ci/memory.ld b/core/embed/bootloader/memory_stm32f4.ld similarity index 74% rename from core/embed/bootloader_ci/memory.ld rename to core/embed/bootloader/memory_stm32f4.ld index 8a05c75c46e..36628081463 100644 --- a/core/embed/bootloader_ci/memory.ld +++ b/core/embed/bootloader/memory_stm32f4.ld @@ -9,7 +9,9 @@ MEMORY { SRAM (wal) : ORIGIN = 0x20000000, LENGTH = 192K } -main_stack_base = ORIGIN(CCMRAM) + LENGTH(CCMRAM); /* 8-byte aligned full descending stack */ +main_stack_base = ORIGIN(CCMRAM) + SIZEOF(.stack) ; /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(CCMRAM); +_estack = main_stack_base; /* used by the startup code to populate variables used by the C code */ data_lma = LOADADDR(.data); @@ -44,17 +46,32 @@ SECTIONS { . = ALIGN(512); } >FLASH AT>FLASH + .stack : ALIGN(8) { + . = 16K; /* Exactly 16K allocated for stack. Overflow causes MemManage fault (when using MPU). */ + } >CCMRAM + .data : ALIGN(4) { *(.data*); . = ALIGN(512); } >CCMRAM AT>FLASH + /DISCARD/ : { + *(.ARM.exidx*); + } + .bss : ALIGN(4) { *(.bss*); . = ALIGN(4); } >CCMRAM - .stack : ALIGN(8) { - . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ - } >CCMRAM + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM + + .boot_args : ALIGN(8) { + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS + } diff --git a/core/embed/bootloader/memory_stm32u58.ld b/core/embed/bootloader/memory_stm32u58.ld new file mode 100644 index 00000000000..e5bc29b3015 --- /dev/null +++ b/core/embed/bootloader/memory_stm32u58.ld @@ -0,0 +1,106 @@ +/* Trezor v2 bootloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K + SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); + +SECTIONS { + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/bootloader/memory_stm32u5a.ld b/core/embed/bootloader/memory_stm32u5a.ld new file mode 100644 index 00000000000..ad08bdd67ff --- /dev/null +++ b/core/embed/bootloader/memory_stm32u5a.ld @@ -0,0 +1,112 @@ +/* Trezor v2 bootloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0 + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); + +SECTIONS { + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index 040326be344..76fa4d5f78c 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -24,7 +24,7 @@ #include #include "messages.pb.h" -#include "boot_internal.h" +#include "boot_args.h" #include "common.h" #include "flash.h" #include "image.h" @@ -598,16 +598,16 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, secbool is_ilu = secfalse; // interaction-less update - if (g_boot_command == BOOT_COMMAND_INSTALL_UPGRADE) { - BLAKE2S_CTX ctx; - uint8_t hash[BLAKE2S_DIGEST_LENGTH]; - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); - blake2s_Update(&ctx, CHUNK_BUFFER_PTR, - vhdr.hdrlen + received_hdr->hdrlen); - blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); + if (bootargs_get_command() == BOOT_COMMAND_INSTALL_UPGRADE) { + IMAGE_HASH_CTX ctx; + uint8_t hash[IMAGE_HASH_DIGEST_LENGTH]; + IMAGE_HASH_INIT(&ctx); + IMAGE_HASH_UPDATE(&ctx, CHUNK_BUFFER_PTR, + vhdr.hdrlen + received_hdr->hdrlen); + IMAGE_HASH_FINAL(&ctx, hash); // the firmware must be the same as confirmed by the user - if (memcmp(&g_boot_args[0], hash, sizeof(hash)) != 0) { + if (memcmp(bootargs_get_args()->hash, hash, sizeof(hash)) != 0) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); MSG_SEND_ASSIGN_STRING(message, "Firmware mismatch"); @@ -637,7 +637,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, is_ilu = sectrue; } -#ifdef USE_OPTIGA +#if defined USE_OPTIGA && !defined STM32U5 if (sectrue != secret_wiped() && ((vhdr.vtrust & VTRUST_SECRET) != 0)) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); @@ -666,6 +666,9 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, // if firmware is not upgrade, erase storage if (sectrue != should_keep_seed) { +#ifdef STM32U5 + secret_bhk_regenerate(); +#endif ensure(flash_area_erase_bulk(STORAGE_AREAS, STORAGE_AREAS_COUNT, NULL), NULL); } @@ -834,7 +837,7 @@ void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { MSG_SEND(Failure); } -#ifdef USE_OPTIGA +#if defined USE_OPTIGA && !defined STM32U5 void process_msg_UnlockBootloader(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { secret_erase(); diff --git a/core/embed/bootloader/startup.s b/core/embed/bootloader/startup_stm32f4.s similarity index 90% rename from core/embed/bootloader/startup.s rename to core/embed/bootloader/startup_stm32f4.s index bb2d3ef6ce8..a1fb0c7e551 100644 --- a/core/embed/bootloader/startup.s +++ b/core/embed/bootloader/startup_stm32f4.s @@ -33,9 +33,9 @@ reset_handler: // subsequent operations, it is not necessary to insert a memory barrier instruction." cpsie f - // r11 contains argument passed to reboot_to_bootloader() + // r11 contains the command passed to bootargs_set() // function called when the firmware rebooted to the bootloader - ldr r0, =g_boot_command + ldr r0, =g_boot_command_shadow str r11, [r0] // enter the application code @@ -43,12 +43,5 @@ reset_handler: b shutdown_privileged - .bss - - .global g_boot_command -g_boot_command: - .word 0 - - .end diff --git a/core/embed/bootloader/startup_stm32u5.s b/core/embed/bootloader/startup_stm32u5.s new file mode 100644 index 00000000000..ee50183b0db --- /dev/null +++ b/core/embed/bootloader/startup_stm32u5.s @@ -0,0 +1,77 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #16 // padding + msr MSPLIM, r0 + + // setup environment for subsequent stage of code + ldr r2, =0 // r2 - the word-sized value to be written + + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + // copy data in from flash + ldr r0, =data_vma // dst addr + ldr r1, =data_lma // src addr + ldr r2, =data_size // size in bytes + bl memcpy + + // copy sensitive data in from flash + ldr r0, =sensitive_vma // dst addr + ldr r1, =sensitive_lma // src addr + ldr r2, =sensitive_size // size in bytes + bl memcpy + + // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value + bl rng_get + ldr r1, = __stack_chk_guard + str r0, [r1] + + // copy & clear g_boot_command + ldr r0, =g_boot_command + ldr r1, [r0] + ldr r0, =g_boot_command_shadow + str r1, [r0] + ldr r0, =g_boot_command + mov r1, #0 + str r1, [r0] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/bootloader_ci/.changelog.d/3370.added b/core/embed/bootloader_ci/.changelog.d/3370.added new file mode 100644 index 00000000000..20f7c864664 --- /dev/null +++ b/core/embed/bootloader_ci/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c index 8285a99af7d..40c56d58a94 100644 --- a/core/embed/bootloader_ci/main.c +++ b/core/embed/bootloader_ci/main.c @@ -23,6 +23,7 @@ #include "common.h" #include "display.h" #include "flash.h" +#include "flash_otp.h" #include "image.h" #include "mini_printf.h" #include "mpu.h" @@ -38,6 +39,11 @@ #include "bootui.h" #include "messages.h" #include "model.h" + +#ifdef USE_HASH_PROCESSOR +#include "hash_processor.h" +#endif + // #include "mpu.h" #define USB_IFACE_NUM 0 @@ -206,6 +212,10 @@ int main(void) { touch_power_on(); #endif +#ifdef USE_HASH_PROCESSOR + hash_processor_init(); +#endif + mpu_config_bootloader(); #if PRODUCTION diff --git a/core/embed/bootloader/memory.ld b/core/embed/bootloader_ci/memory_stm32f4.ld similarity index 92% rename from core/embed/bootloader/memory.ld rename to core/embed/bootloader_ci/memory_stm32f4.ld index b96888c7e5f..d66d8bfc38d 100644 --- a/core/embed/bootloader/memory.ld +++ b/core/embed/bootloader_ci/memory_stm32f4.ld @@ -10,6 +10,8 @@ MEMORY { } main_stack_base = ORIGIN(CCMRAM) + SIZEOF(.stack) ; /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(CCMRAM); +_estack = main_stack_base; /* used by the startup code to populate variables used by the C code */ data_lma = LOADADDR(.data); @@ -27,7 +29,6 @@ sram_end = ORIGIN(SRAM) + LENGTH(SRAM); /* reserve 256 bytes for bootloader arguments */ boot_args_start = ORIGIN(BOOT_ARGS); boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); -g_boot_args = boot_args_start; _codelen = SIZEOF(.flash) + SIZEOF(.data); @@ -68,4 +69,8 @@ SECTIONS { . = ALIGN(4); } >SRAM + .boot_args : ALIGN(8) { + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS } diff --git a/core/embed/bootloader_ci/memory_stm32u58.ld b/core/embed/bootloader_ci/memory_stm32u58.ld new file mode 100644 index 00000000000..1ca7b185b5a --- /dev/null +++ b/core/embed/bootloader_ci/memory_stm32u58.ld @@ -0,0 +1,106 @@ +/* Trezor v2 bootloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K + SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); + +SECTIONS { + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Exactly 16K allocated for stack. Overflow causes Usage fault. */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/bootloader_ci/memory_stm32u5a.ld b/core/embed/bootloader_ci/memory_stm32u5a.ld new file mode 100644 index 00000000000..ad08bdd67ff --- /dev/null +++ b/core/embed/bootloader_ci/memory_stm32u5a.ld @@ -0,0 +1,112 @@ +/* Trezor v2 bootloader linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C010000, LENGTH = 128K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0 + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); + +SECTIONS { + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/bootloader_ci/startup.s b/core/embed/bootloader_ci/startup_stm32f4.s similarity index 100% rename from core/embed/bootloader_ci/startup.s rename to core/embed/bootloader_ci/startup_stm32f4.s diff --git a/core/embed/bootloader_ci/startup_stm32u5.s b/core/embed/bootloader_ci/startup_stm32u5.s new file mode 100644 index 00000000000..e8c04834e47 --- /dev/null +++ b/core/embed/bootloader_ci/startup_stm32u5.s @@ -0,0 +1,68 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #16 // padding + msr MSPLIM, r0 + + // setup environment for subsequent stage of code + ldr r2, =0 // r2 - the word-sized value to be written + + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + // copy data in from flash + ldr r0, =data_vma // dst addr + ldr r1, =data_lma // src addr + ldr r2, =data_size // size in bytes + bl memcpy + + // copy sensitive data in from flash + ldr r0, =sensitive_vma // dst addr + ldr r1, =sensitive_lma // src addr + ldr r2, =sensitive_size // size in bytes + bl memcpy + + // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value + bl rng_get + ldr r1, = __stack_chk_guard + str r0, [r1] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/extmod/modtrezorio/modtrezorio-flash.h b/core/embed/extmod/modtrezorio/modtrezorio-flash.h index 2c2c955d9ea..3815f1e7124 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-flash.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-flash.h @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#include "flash.h" +#include "flash_otp.h" #include "embed/extmod/trezorobj.h" diff --git a/core/embed/extmod/modtrezorutils/modtrezorutils.c b/core/embed/extmod/modtrezorutils/modtrezorutils.c index 00110718e90..2cde2041aaf 100644 --- a/core/embed/extmod/modtrezorutils/modtrezorutils.c +++ b/core/embed/extmod/modtrezorutils/modtrezorutils.c @@ -253,6 +253,16 @@ STATIC mp_obj_t mod_trezorutils_unit_btconly(void) { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_unit_btconly_obj, mod_trezorutils_unit_btconly); +/// def sd_hotswap_enabled() -> bool: +/// """ +/// Returns True if SD card hot swapping is enabled +/// """ +STATIC mp_obj_t mod_trezorutils_sd_hotswap_enabled(void) { + return unit_variant_is_sd_hotswap_enabled() ? mp_const_true : mp_const_false; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_sd_hotswap_enabled_obj, + mod_trezorutils_sd_hotswap_enabled); + /// def reboot_to_bootloader( /// boot_command : int = 0, /// boot_args : bytes | None = None, @@ -286,7 +296,8 @@ STATIC mp_obj_t mod_trezorutils_reboot_to_bootloader(size_t n_args, mp_get_buffer_raise(args[1], &boot_args, MP_BUFFER_READ); } - svc_reboot_to_bootloader(boot_command, boot_args.buf, boot_args.len); + bootargs_set(boot_command, boot_args.buf, boot_args.len); + svc_reboot_to_bootloader(); #endif return mp_const_none; } @@ -414,6 +425,8 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { MP_ROM_PTR(&mod_trezorutils_unit_color_obj)}, {MP_ROM_QSTR(MP_QSTR_unit_btconly), MP_ROM_PTR(&mod_trezorutils_unit_btconly_obj)}, + {MP_ROM_QSTR(MP_QSTR_sd_hotswap_enabled), + MP_ROM_PTR(&mod_trezorutils_sd_hotswap_enabled_obj)}, // various built-in constants {MP_ROM_QSTR(MP_QSTR_SCM_REVISION), MP_ROM_PTR(&mod_trezorutils_revision_obj)}, diff --git a/core/embed/firmware/bl_check.c b/core/embed/firmware/bl_check.c index 205093739eb..c87bf25cadb 100644 --- a/core/embed/firmware/bl_check.c +++ b/core/embed/firmware/bl_check.c @@ -217,25 +217,27 @@ void check_and_replace_bootloader(void) { do { uint32_t *p = decomp_out; - uint32_t last_whole_word_addr = (((uint32_t)decomp.dest) & ~3); + uint32_t last_whole_word_addr = (((uint32_t)decomp.dest) & ~0x7F); while ((uint32_t)p < last_whole_word_addr) { - ensure(flash_area_write_word(&BOOTLOADER_AREA, offset, *p++), NULL); - offset += sizeof(uint32_t); + ensure(flash_area_write_burst(&BOOTLOADER_AREA, offset, p), NULL); + p += FLASH_BURST_LENGTH; + offset += FLASH_BURST_LENGTH * sizeof(uint32_t); } if ((uint8_t *)p < decomp.dest) { // last few bytes in case of unaligned data - uint32_t d = 0; + uint32_t d[FLASH_BURST_LENGTH] = {0}; memcpy(&d, p, (uint32_t)decomp.dest - (uint32_t)p); - ensure(flash_area_write_word(&BOOTLOADER_AREA, offset, d), NULL); - offset += sizeof(uint32_t); + ensure(flash_area_write_burst(&BOOTLOADER_AREA, offset, d), NULL); + offset += FLASH_BURST_LENGTH * sizeof(uint32_t); } decomp.dest = (uint8_t *)decomp_out; } while (uzlib_uncompress(&decomp) >= 0); + uint32_t d[FLASH_BURST_LENGTH] = {0}; // fill the rest of the bootloader area with 0x00 while (offset < bl_len) { - ensure(flash_area_write_word(&BOOTLOADER_AREA, offset, 0x00000000), NULL); - offset += sizeof(uint32_t); + ensure(flash_area_write_burst(&BOOTLOADER_AREA, offset, d), NULL); + offset += FLASH_BURST_LENGTH * sizeof(uint32_t); } ensure(flash_lock_write(), NULL); diff --git a/core/embed/firmware/bootloaders/bootloader_T3T1.bin b/core/embed/firmware/bootloaders/bootloader_T3T1.bin new file mode 100644 index 00000000000..304db439e28 Binary files /dev/null and b/core/embed/firmware/bootloaders/bootloader_T3T1.bin differ diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index f21fdeac8bb..db1d244eb97 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -41,6 +41,7 @@ #include "common.h" #include "compiler_traits.h" #include "display.h" +#include "fault_handlers.h" #include "flash.h" #include "image.h" #include "memzero.h" @@ -48,6 +49,7 @@ #include "mpu.h" #include "random_delays.h" #include "rust_ui.h" +#include "secure_aes.h" #include TREZOR_BOARD @@ -72,11 +74,18 @@ #ifdef USE_SD_CARD #include "sdcard.h" #endif +#ifdef USE_HASH_PROCESSOR +#include "hash_processor.h" +#endif + #ifdef USE_OPTIGA #include "optiga_commands.h" #include "optiga_transport.h" +#endif +#if defined USE_OPTIGA | defined STM32U5 #include "secret.h" #endif + #include "unit_variant.h" #ifdef SYSTEM_VIEW @@ -88,6 +97,9 @@ #ifdef USE_SECP256K1_ZKP #include "zkp_context.h" #endif +#ifdef USE_HAPTIC +#include "haptic.h" +#endif // from util.s extern void shutdown_privileged(void); @@ -99,17 +111,23 @@ int main(void) { rdi_start(); #endif +#ifdef STM32U5 + check_oem_keys(); +#endif + // reinitialize HAL for Trezor One #if defined TREZOR_MODEL_1 HAL_Init(); #endif - collect_hw_entropy(); - #ifdef SYSTEM_VIEW enable_systemview(); #endif +#ifdef USE_HASH_PROCESSOR + hash_processor_init(); +#endif + #ifdef USE_DMA2D dma2d_init(); #endif @@ -125,10 +143,13 @@ int main(void) { #ifdef USE_OPTIGA uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; - secbool secret_ok = - secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); + secbool secret_ok = secret_optiga_extract(secret); #endif + mpu_config_firmware_initial(); + + collect_hw_entropy(); + #if PRODUCTION || BOOTLOADER_QA check_and_replace_bootloader(); #endif @@ -139,15 +160,16 @@ int main(void) { // Init peripherals pendsv_init(); -#if !PRODUCTION - // enable BUS fault and USAGE fault handlers - SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); -#endif + fault_handlers_init(); #if defined TREZOR_MODEL_T set_core_clock(CLOCK_180_MHZ); #endif +#ifdef STM32U5 + secure_aes_init(); +#endif + #ifdef USE_BUTTON button_init(); #endif @@ -172,6 +194,10 @@ int main(void) { sdcard_init(); #endif +#ifdef USE_HAPTIC + haptic_init(); +#endif + #ifdef USE_OPTIGA optiga_init(); optiga_open_application(); @@ -231,25 +257,6 @@ void __attribute__((noreturn)) nlr_jump_fail(void *val) { error_shutdown("INTERNAL ERROR", "(UE)"); } -// interrupt handlers - -void NMI_Handler(void) { - // Clock Security System triggered NMI - if ((RCC->CIR & RCC_CIR_CSSF) != 0) { - error_shutdown("INTERNAL ERROR", "(CS)"); - } -} - -void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } - -void MemManage_Handler_MM(void) { error_shutdown("INTERNAL ERROR", "(MM)"); } - -void MemManage_Handler_SO(void) { error_shutdown("INTERNAL ERROR", "(SO)"); } - -void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(BF)"); } - -void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(UF)"); } - // MicroPython builtin stubs mp_import_stat_t mp_import_stat(const char *path) { diff --git a/core/embed/firmware/memory_DISC2.ld b/core/embed/firmware/memory_DISC2.ld new file mode 100644 index 00000000000..450579b4e94 --- /dev/null +++ b/core/embed/firmware/memory_DISC2.ld @@ -0,0 +1,128 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0 + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM1 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram1_end); /* this explicitly sets the end of the heap */ + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/firmware/memory_T.ld b/core/embed/firmware/memory_T.ld index fa557dccd14..8f65dd6c17d 100644 --- a/core/embed/firmware/memory_T.ld +++ b/core/embed/firmware/memory_T.ld @@ -96,4 +96,9 @@ SECTIONS { *(.no_dma_buffers*); . = ALIGN(4); } >CCMRAM + + .boot_args : ALIGN(8) { + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS } diff --git a/core/embed/firmware/memory_T3T1.ld b/core/embed/firmware/memory_T3T1.ld new file mode 100644 index 00000000000..1f8abef7dd3 --- /dev/null +++ b/core/embed/firmware/memory_T3T1.ld @@ -0,0 +1,122 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 1664K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K + SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram3_end); /* this explicitly sets the end of the heap */ + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/firmware/startup.S b/core/embed/firmware/startup_stm32f4.S similarity index 90% rename from core/embed/firmware/startup.S rename to core/embed/firmware/startup_stm32f4.S index dbed46bb259..7d0fadf2cda 100644 --- a/core/embed/firmware/startup.S +++ b/core/embed/firmware/startup_stm32f4.S @@ -66,16 +66,4 @@ reset_handler: b shutdown_privileged - .global MemManage_Handler - .type MemManage_Handler, STT_FUNC -MemManage_Handler: - ldr r2, =_sstack - mrs r1, msp - ldr r0, =_estack - msr msp, r0 - cmp r1, r2 - IT lt - bllt MemManage_Handler_SO - bl MemManage_Handler_MM - .end diff --git a/core/embed/firmware/startup_stm32u5.S b/core/embed/firmware/startup_stm32u5.S new file mode 100644 index 00000000000..19e183adcf0 --- /dev/null +++ b/core/embed/firmware/startup_stm32u5.S @@ -0,0 +1,72 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #16 // padding + msr MSPLIM, r0 + + // setup environment for subsequent stage of code + ldr r2, =0 // r2 - the word-sized value to be written + + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + // copy data in from flash + ldr r0, =data_vma // dst addr + ldr r1, =data_lma // src addr + ldr r2, =data_size // size in bytes + bl memcpy + + // copy sensitive data in from flash + ldr r0, =sensitive_vma // dst addr + ldr r1, =sensitive_lma // src addr + ldr r2, =sensitive_size // size in bytes + bl memcpy + + // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value + bl rng_get + ldr r1, = __stack_chk_guard + str r0, [r1] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/trezorhal/stm32f4/compiler_traits.h b/core/embed/lib/compiler_traits.h similarity index 100% rename from core/embed/trezorhal/stm32f4/compiler_traits.h rename to core/embed/lib/compiler_traits.h diff --git a/core/embed/lib/image.c b/core/embed/lib/image.c index 3b15ef6db5f..c2eaad3ab83 100644 --- a/core/embed/lib/image.c +++ b/core/embed/lib/image.c @@ -19,7 +19,6 @@ #include -#include "blake2s.h" #include "ed25519-donna/ed25519.h" #include "common.h" @@ -120,13 +119,13 @@ secbool check_image_model(const image_header *const hdr) { } void get_image_fingerprint(const image_header *const hdr, uint8_t *const out) { - BLAKE2S_CTX ctx; - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); - blake2s_Update(&ctx, hdr, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE); + IMAGE_HASH_CTX ctx; + IMAGE_HASH_INIT(&ctx); + IMAGE_HASH_UPDATE(&ctx, (uint8_t *)hdr, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE); for (int i = 0; i < IMAGE_SIG_SIZE; i++) { - blake2s_Update(&ctx, (const uint8_t *)"\x00", 1); + IMAGE_HASH_UPDATE(&ctx, (const uint8_t *)"\x00", 1); } - blake2s_Final(&ctx, out, BLAKE2S_DIGEST_LENGTH); + IMAGE_HASH_FINAL(&ctx, out); } secbool check_image_header_sig(const image_header *const hdr, uint8_t key_m, @@ -141,7 +140,7 @@ secbool check_image_header_sig(const image_header *const hdr, uint8_t key_m, return secfalse; return sectrue * - (0 == ed25519_sign_open(fingerprint, BLAKE2S_DIGEST_LENGTH, pub, + (0 == ed25519_sign_open(fingerprint, IMAGE_HASH_DIGEST_LENGTH, pub, *(const ed25519_signature *)hdr->sig)); } @@ -199,21 +198,21 @@ secbool check_vendor_header_sig(const vendor_header *const vhdr, uint8_t key_m, // check header signature - uint8_t hash[BLAKE2S_DIGEST_LENGTH]; - BLAKE2S_CTX ctx; - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); - blake2s_Update(&ctx, vhdr->origin, vhdr->hdrlen - IMAGE_SIG_SIZE); + uint8_t hash[IMAGE_HASH_DIGEST_LENGTH]; + IMAGE_HASH_CTX ctx; + IMAGE_HASH_INIT(&ctx); + IMAGE_HASH_UPDATE(&ctx, vhdr->origin, vhdr->hdrlen - IMAGE_SIG_SIZE); for (int i = 0; i < IMAGE_SIG_SIZE; i++) { - blake2s_Update(&ctx, (const uint8_t *)"\x00", 1); + IMAGE_HASH_UPDATE(&ctx, (const uint8_t *)"\x00", 1); } - blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); + IMAGE_HASH_FINAL(&ctx, hash); ed25519_public_key pub; if (sectrue != compute_pubkey(key_m, key_n, keys, vhdr->sigmask, pub)) return secfalse; return sectrue * - (0 == ed25519_sign_open(hash, BLAKE2S_DIGEST_LENGTH, pub, + (0 == ed25519_sign_open(hash, IMAGE_HASH_DIGEST_LENGTH, pub, *(const ed25519_signature *)vhdr->sig)); } @@ -223,20 +222,22 @@ secbool check_vendor_header_keys(const vendor_header *const vhdr) { } void vendor_header_hash(const vendor_header *const vhdr, uint8_t *hash) { - BLAKE2S_CTX ctx; - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); - blake2s_Update(&ctx, vhdr->vstr, vhdr->vstr_len); - blake2s_Update(&ctx, "Trezor Vendor Header", 20); - blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); + IMAGE_HASH_CTX ctx; + IMAGE_HASH_INIT(&ctx); + IMAGE_HASH_UPDATE(&ctx, (const uint8_t *)vhdr->vstr, vhdr->vstr_len); + IMAGE_HASH_UPDATE(&ctx, (const uint8_t *)"Trezor Vendor Header", 20); + IMAGE_HASH_FINAL(&ctx, hash); } secbool check_single_hash(const uint8_t *const hash, const uint8_t *const data, int len) { - uint8_t h[BLAKE2S_DIGEST_LENGTH]; - blake2s(data, len, h, BLAKE2S_DIGEST_LENGTH); - return sectrue * (0 == memcmp(h, hash, BLAKE2S_DIGEST_LENGTH)); + uint8_t s_c[IMAGE_HASH_DIGEST_LENGTH] = {0}; + + IMAGE_HASH_CALC(data, len, s_c); + + return sectrue * (0 == memcmp(s_c, hash, IMAGE_HASH_DIGEST_LENGTH)); } -// + secbool check_image_contents(const image_header *const hdr, uint32_t firstskip, const flash_area_t *area) { if (0 == area) { @@ -279,23 +280,42 @@ secbool check_image_contents(const image_header *const hdr, uint32_t firstskip, return secfalse; } + uint32_t expected_word = expected_byte << 24 | expected_byte << 16 | + expected_byte << 8 | expected_byte; + while (offset < end_offset) { size_t bytes_to_check = MIN( IMAGE_CHUNK_SIZE - (offset % IMAGE_CHUNK_SIZE), end_offset - offset); + size_t words_to_check = bytes_to_check / sizeof(uint32_t); + size_t single_bytes_to_check = bytes_to_check % sizeof(uint32_t); + + const uint8_t *bytes = (const uint8_t *)flash_area_get_address( + area, offset, single_bytes_to_check); + if (!bytes) { + return secfalse; + } + + for (size_t i = 0; i < single_bytes_to_check; i++) { + if (bytes[i] != expected_byte) { + return secfalse; + } + } + + offset += single_bytes_to_check; - const uint8_t *data = - (const uint8_t *)flash_area_get_address(area, offset, bytes_to_check); + const uint32_t *data = (const uint32_t *)flash_area_get_address( + area, offset, bytes_to_check - single_bytes_to_check); if (!data) { return secfalse; } - for (size_t i = 0; i < bytes_to_check; i++) { - if (data[i] != expected_byte) { + for (size_t i = 0; i < words_to_check; i++) { + if (data[i] != expected_word) { return secfalse; } } - offset += bytes_to_check; + offset += words_to_check * sizeof(uint32_t); } } @@ -340,10 +360,7 @@ secbool check_firmware_header(const uint8_t *header, size_t header_size, get_image_fingerprint(ihdr, info->fingerprint); // calculate hash of both vendor and image headers - BLAKE2S_CTX ctx; - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); - blake2s_Update(&ctx, header, vhdr.hdrlen + ihdr->hdrlen); - blake2s_Final(&ctx, &info->hash, BLAKE2S_DIGEST_LENGTH); + IMAGE_HASH_CALC(header, vhdr.hdrlen + ihdr->hdrlen, info->hash); return sectrue; } diff --git a/core/embed/lib/image.h b/core/embed/lib/image.h index 326b4bb5247..bb6c58a3965 100644 --- a/core/embed/lib/image.h +++ b/core/embed/lib/image.h @@ -23,6 +23,7 @@ #include #include "blake2s.h" #include "flash.h" +#include "image_hash_conf.h" #include "model.h" #include "secbool.h" @@ -90,9 +91,9 @@ typedef struct { uint8_t ver_patch; uint8_t ver_build; // firmware fingerprint - uint8_t fingerprint[BLAKE2S_DIGEST_LENGTH]; + uint8_t fingerprint[IMAGE_HASH_DIGEST_LENGTH]; // hash of vendor and image header - uint8_t hash[BLAKE2S_DIGEST_LENGTH]; + uint8_t hash[IMAGE_HASH_DIGEST_LENGTH]; } firmware_header_info_t; const image_header *read_image_header(const uint8_t *const data, diff --git a/core/embed/lib/image_hash_conf.h b/core/embed/lib/image_hash_conf.h new file mode 100644 index 00000000000..1fab5efabd9 --- /dev/null +++ b/core/embed/lib/image_hash_conf.h @@ -0,0 +1,41 @@ +#ifndef LIB_IMAGE_HASH_H_ +#define LIB_IMAGE_HASH_H_ + +#include "model.h" +#include TREZOR_BOARD + +#ifdef IMAGE_HASH_SHA256 +#include "sha2.h" +#define IMAGE_HASH_DIGEST_LENGTH SHA256_DIGEST_LENGTH +#ifdef USE_HASH_PROCESSOR +#include "hash_processor.h" +#define IMAGE_HASH_CTX hash_sha265_context_t +#define IMAGE_HASH_INIT(ctx) hash_processor_sha256_init(ctx) +#define IMAGE_HASH_UPDATE(ctx, data, len) \ + hash_processor_sha256_update(ctx, data, len) +#define IMAGE_HASH_FINAL(ctx, output) hash_processor_sha256_final(ctx, output) +#define IMAGE_HASH_CALC(data, len, output) \ + hash_processor_sha256_calc(data, len, output) +#else +#define IMAGE_HASH_CTX SHA256_CTX +#define IMAGE_HASH_INIT(ctx) sha256_Init(ctx) +#define IMAGE_HASH_UPDATE(ctx, data, len) sha256_Update(ctx, data, len) +#define IMAGE_HASH_FINAL(ctx, output) sha256_Final(ctx, output) +#define IMAGE_HASH_CALC(data, len, output) sha256_Raw(data, len, output) +#endif + +#elif defined IMAGE_HASH_BLAKE2S +#include "blake2s.h" +#define IMAGE_HASH_DIGEST_LENGTH BLAKE2S_DIGEST_LENGTH +#define IMAGE_HASH_CTX BLAKE2S_CTX +#define IMAGE_HASH_INIT(ctx) blake2s_Init(ctx, BLAKE2S_DIGEST_LENGTH) +#define IMAGE_HASH_UPDATE(ctx, data, len) blake2s_Update(ctx, data, len) +#define IMAGE_HASH_FINAL(ctx, output) \ + blake2s_Final(ctx, output, BLAKE2S_DIGEST_LENGTH) +#define IMAGE_HASH_CALC(data, len, output) \ + blake2s(data, len, output, BLAKE2S_DIGEST_LENGTH) +#else +#error "IMAGE_HASH_SHA256 or IMAGE_HASH_BLAKE2S must be defined" +#endif + +#endif diff --git a/core/embed/lib/sizedefs.h b/core/embed/lib/sizedefs.h new file mode 100644 index 00000000000..9f8bb7a6c57 --- /dev/null +++ b/core/embed/lib/sizedefs.h @@ -0,0 +1,24 @@ +#ifndef SIZEDEFS_H_ +#define SIZEDEFS_H_ + +#define SIZE_2K (2 * 1024) +#define SIZE_16K (16 * 1024) +#define SIZE_48K (48 * 1024) +#define SIZE_64K (64 * 1024) +#define SIZE_128K (128 * 1024) +#define SIZE_192K (192 * 1024) +#define SIZE_256K (256 * 1024) +#define SIZE_320K (320 * 1024) +#define SIZE_768K (768 * 1024) +#define SIZE_2496K (2496 * 1024) +#define SIZE_3712K ((4096 - 384) * 1024) +#define SIZE_3776K ((4096 - 320) * 1024) +#define SIZE_3904K ((4096 - 192) * 1024) +#define SIZE_4032K ((4096 - 64) * 1024) +#define SIZE_2M (2 * 1024 * 1024) +#define SIZE_4M (4 * 1024 * 1024) +#define SIZE_16M (16 * 1024 * 1024) +#define SIZE_256M (256 * 1024 * 1024) +#define SIZE_512M (512 * 1024 * 1024) + +#endif diff --git a/core/embed/trezorhal/stm32f4/translations.c b/core/embed/lib/translations.c similarity index 61% rename from core/embed/trezorhal/stm32f4/translations.c rename to core/embed/lib/translations.c index d01debbf4bf..108b318a62a 100644 --- a/core/embed/trezorhal/stm32f4/translations.c +++ b/core/embed/lib/translations.c @@ -13,11 +13,24 @@ bool translations_write(const uint8_t* data, uint32_t offset, uint32_t len) { } ensure(flash_unlock_write(), "translations_write unlock"); - for (int i = 0; i < len; i++) { - // TODO optimize by writing by (quad)words - ensure(flash_area_write_byte(&TRANSLATIONS_AREA, offset + i, data[i]), + for (int i = 0; i < (len / FLASH_BLOCK_SIZE); i++) { + // todo consider alignment + ensure(flash_area_write_block(&TRANSLATIONS_AREA, + offset + (i * FLASH_BLOCK_SIZE), + (const uint32_t*)&data[i * FLASH_BLOCK_SIZE]), "translations_write write"); } + + if (len % FLASH_BLOCK_SIZE) { + flash_block_t block = {0}; + memset(block, 0xFF, FLASH_BLOCK_SIZE); + memcpy(block, data + (len / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE, + len % FLASH_BLOCK_SIZE); + ensure(flash_area_write_block( + &TRANSLATIONS_AREA, + offset + (len / FLASH_BLOCK_SIZE) * FLASH_BLOCK_SIZE, block), + "translations_write write rest"); + } ensure(flash_lock_write(), "translations_write lock"); return true; } diff --git a/core/embed/trezorhal/translations.h b/core/embed/lib/translations.h similarity index 100% rename from core/embed/trezorhal/translations.h rename to core/embed/lib/translations.h diff --git a/core/embed/lib/unit_variant.c b/core/embed/lib/unit_variant.c index 8e1b51a04d6..2a2bb4d767a 100644 --- a/core/embed/lib/unit_variant.c +++ b/core/embed/lib/unit_variant.c @@ -1,23 +1,61 @@ -#include "unit_variant.h" -#include "flash.h" +#include + +#include "flash_otp.h" #include "model.h" +#include "unit_variant.h" +#include TREZOR_BOARD static uint8_t unit_variant_color = 0; static bool unit_variant_btconly = false; static bool unit_variant_ok = false; +static int16_t unit_variant_build_year = -1; + static void unit_variant_0x01(const uint8_t *data) { unit_variant_color = data[1]; unit_variant_btconly = data[2] == 1; unit_variant_ok = true; } +static int16_t unit_variant_get_build_year(void) { + uint8_t data[FLASH_OTP_BLOCK_SIZE] = {0}; + + secbool result = + flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, data, FLASH_OTP_BLOCK_SIZE); + + if (sectrue != result || data[0] == 0xFF) { + return -1; + } + + /** + * Expecting format {MODEL_IDENTIFIER}-YYMMDD + * + * See also + * https://docs.trezor.io/trezor-firmware/core/misc/memory.html?highlight=otp#otp + */ + + size_t len = strnlen((char *)data, FLASH_OTP_BLOCK_SIZE); + + for (int i = 0; i < len; i++) { + if (data[i] == '-') { + if ((len - (i + 1)) != 6) { + return -1; + } + return ((int16_t)data[i + 1] - (int16_t)'0') * 10 + + ((int16_t)data[i + 2] - (int16_t)'0'); + } + } + return -1; +} + void unit_variant_init(void) { uint8_t data[FLASH_OTP_BLOCK_SIZE]; secbool result = flash_otp_read(FLASH_OTP_BLOCK_DEVICE_VARIANT, 0, data, FLASH_OTP_BLOCK_SIZE); + unit_variant_build_year = unit_variant_get_build_year(); + if (sectrue == result) { switch (data[0]) { case 0x01: @@ -34,3 +72,20 @@ uint8_t unit_variant_get_color(void) { return unit_variant_color; } bool unit_variant_get_btconly(void) { return unit_variant_btconly; } bool unit_variant_present(void) { return unit_variant_ok; } + +bool unit_variant_is_sd_hotswap_enabled(void) { +#ifndef USE_SD_CARD + return false; +#else +#ifdef TREZOR_MODEL_T + // early produced TTs have a HW bug that prevents hotswapping of the SD card, + // lets check the build data and decide based on that + if (unit_variant_build_year <= 18) { + return false; + } + return true; +#else + return true; +#endif +#endif +} diff --git a/core/embed/lib/unit_variant.h b/core/embed/lib/unit_variant.h index 110af266026..72915a8a371 100644 --- a/core/embed/lib/unit_variant.h +++ b/core/embed/lib/unit_variant.h @@ -9,4 +9,6 @@ bool unit_variant_present(void); uint8_t unit_variant_get_color(void); bool unit_variant_get_btconly(void); +bool unit_variant_is_sd_hotswap_enabled(void); + #endif //_UNIT_VARIANT_H diff --git a/core/embed/models/layout_common.h b/core/embed/models/layout_common.h index 898338eeb5d..e95f868bf0f 100644 --- a/core/embed/models/layout_common.h +++ b/core/embed/models/layout_common.h @@ -1,7 +1,7 @@ #ifndef LAYOUT_COMMON_H #define LAYOUT_COMMON_H -#include "flash.h" +#include "flash_area.h" // OTP blocks allocation #define FLASH_OTP_BLOCK_BATCH 0 @@ -15,6 +15,7 @@ extern const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT]; extern const flash_area_t BOARDLOADER_AREA; extern const flash_area_t SECRET_AREA; +extern const flash_area_t BHK_AREA; extern const flash_area_t TRANSLATIONS_AREA; extern const flash_area_t BOOTLOADER_AREA; extern const flash_area_t FIRMWARE_AREA; diff --git a/core/embed/models/model.h b/core/embed/models/model.h index 0739cdf02d4..1b98b8a81c7 100644 --- a/core/embed/models/model.h +++ b/core/embed/models/model.h @@ -9,8 +9,12 @@ #include "model_T2T1.h" #elif defined TREZOR_MODEL_R #include "model_T2B1.h" +#elif defined TREZOR_MODEL_T3T1 +#include "model_T3T1.h" #elif defined TREZOR_MODEL_DISC1 #include "model_D001.h" +#elif defined TREZOR_MODEL_DISC2 +#include "model_D002.h" #else #error Unknown Trezor model #endif diff --git a/core/embed/models/model_D001.h b/core/embed/models/model_D001.h index 15350cbd553..6c52dbc5bce 100644 --- a/core/embed/models/model_D001.h +++ b/core/embed/models/model_D001.h @@ -19,10 +19,12 @@ (const uint8_t *)"\xee\x93\xa4\xf6\x6f\x8d\x16\xb8\x19\xbb\x9b\xeb\x9f\xfc\xcd\xfc\xdc\x14\x12\xe8\x7f\xee\x6a\x32\x4c\x2a\x99\xa1\xe0\xe6\x71\x48", #define BOARDLOADER_START 0x08000000 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 #define IMAGE_CHUNK_SIZE (128 * 1024) +#define IMAGE_HASH_BLAKE2S #define BOOTLOADER_IMAGE_MAXSIZE (128 * 1024 * 1) // 128 KB #define FIRMWARE_IMAGE_MAXSIZE (128 * 1024 * 13) // 1664 KB #define NORCOW_SECTOR_SIZE (64 * 1024) diff --git a/core/embed/models/model_D002.h b/core/embed/models/model_D002.h new file mode 100644 index 00000000000..e8c9c68785b --- /dev/null +++ b/core/embed/models/model_D002.h @@ -0,0 +1,35 @@ +#ifndef MODELS_MODEL_DISC2_H_ +#define MODELS_MODEL_DISC2_H_ + +#include "sizedefs.h" + +#define MODEL_NAME "T" +#define MODEL_FULL_NAME "Trezor Model T" +#define MODEL_INTERNAL_NAME "D002" +#define MODEL_INTERNAL_NAME_TOKEN D002 +#define MODEL_NAME_QSTR MP_QSTR_T +#define MODEL_INTERNAL_NAME_QSTR MP_QSTR_D001 + +/*** Discovery uses DEV keys in any build variant ***/ +#define MODEL_BOARDLOADER_KEYS \ + (const uint8_t *)"\xdb\x99\x5f\xe2\x51\x69\xd1\x41\xca\xb9\xbb\xba\x92\xba\xa0\x1f\x9f\x2e\x1e\xce\x7d\xf4\xcb\x2a\xc0\x51\x90\xf3\x7f\xcc\x1f\x9d", \ + (const uint8_t *)"\x21\x52\xf8\xd1\x9b\x79\x1d\x24\x45\x32\x42\xe1\x5f\x2e\xab\x6c\xb7\xcf\xfa\x7b\x6a\x5e\xd3\x00\x97\x96\x0e\x06\x98\x81\xdb\x12", \ + (const uint8_t *)"\x22\xfc\x29\x77\x92\xf0\xb6\xff\xc0\xbf\xcf\xdb\x7e\xdb\x0c\x0a\xa1\x4e\x02\x5a\x36\x5e\xc0\xe3\x42\xe8\x6e\x38\x29\xcb\x74\xb6", + +#define MODEL_BOOTLOADER_KEYS \ + (const uint8_t *)"\xd7\x59\x79\x3b\xbc\x13\xa2\x81\x9a\x82\x7c\x76\xad\xb6\xfb\xa8\xa4\x9a\xee\x00\x7f\x49\xf2\xd0\x99\x2d\x99\xb8\x25\xad\x2c\x48", \ + (const uint8_t *)"\x63\x55\x69\x1c\x17\x8a\x8f\xf9\x10\x07\xa7\x47\x8a\xfb\x95\x5e\xf7\x35\x2c\x63\xe7\xb2\x57\x03\x98\x4c\xf7\x8b\x26\xe2\x1a\x56", \ + (const uint8_t *)"\xee\x93\xa4\xf6\x6f\x8d\x16\xb8\x19\xbb\x9b\xeb\x9f\xfc\xcd\xfc\xdc\x14\x12\xe8\x7f\xee\x6a\x32\x4c\x2a\x99\xa1\xe0\xe6\x71\x48", + +#define BOARDLOADER_START 0x0C004000 +#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define BOOTLOADER_START 0x0C010000 +#define FIRMWARE_START 0x0C050000 + +#define IMAGE_CHUNK_SIZE SIZE_256K +#define IMAGE_HASH_SHA256 +#define BOOTLOADER_IMAGE_MAXSIZE SIZE_128K +#define FIRMWARE_IMAGE_MAXSIZE SIZE_3712K +#define NORCOW_SECTOR_SIZE SIZE_64K + +#endif diff --git a/core/embed/models/model_D002_layout.c b/core/embed/models/model_D002_layout.c new file mode 100644 index 00000000000..50f6d753dd1 --- /dev/null +++ b/core/embed/models/model_D002_layout.c @@ -0,0 +1,93 @@ +#include "flash.h" +#include "model.h" + +const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = { + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x18, + .num_sectors = 8, + }, + }, + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x20, + .num_sectors = 8, + }, + }, +}; + +const flash_area_t BOARDLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 2, + .num_sectors = 6, + }, +}; + +const flash_area_t BOOTLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x08, + .num_sectors = 16, + }, +}; + +const flash_area_t FIRMWARE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x28, + .num_sectors = 464, + }, +}; + +const flash_area_t SECRET_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0, + .num_sectors = 2, + }, +}; + +const flash_area_t BHK_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 1, + .num_sectors = 1, + }, +}; + +const flash_area_t TRANSLATIONS_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 504, + .num_sectors = 8, + }, +}; + +const flash_area_t WIPE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x18, + .num_sectors = 488, + }, +}; + +const flash_area_t ALL_WIPE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x08, + .num_sectors = 504, + }, +}; diff --git a/core/embed/models/model_T1B1.h b/core/embed/models/model_T1B1.h index 4349803e56f..1138d438363 100644 --- a/core/embed/models/model_T1B1.h +++ b/core/embed/models/model_T1B1.h @@ -11,6 +11,7 @@ #define FIRMWARE_START 0x08010000 #define IMAGE_CHUNK_SIZE (64 * 1024) +#define IMAGE_HASH_SHA256 #define BOOTLOADER_IMAGE_MAXSIZE (32 * 1024 * 1) // 32 KB #define FIRMWARE_IMAGE_MAXSIZE (64 * 1024 * 15) // 960 KB #define NORCOW_SECTOR_SIZE (16 * 1024) diff --git a/core/embed/models/model_T2B1.h b/core/embed/models/model_T2B1.h index 3e996ae917c..cd27202be93 100644 --- a/core/embed/models/model_T2B1.h +++ b/core/embed/models/model_T2B1.h @@ -19,10 +19,12 @@ (const uint8_t *)"\x07\xc8\x51\x34\x94\x6b\xf8\x9f\xa1\x9b\xdc\x2c\x5e\x5f\xf9\xce\x01\x29\x65\x08\xee\x08\x63\xd0\xff\x6d\x63\x33\x1d\x1a\x25\x16", #define BOARDLOADER_START 0x08000000 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 #define IMAGE_CHUNK_SIZE (128 * 1024) +#define IMAGE_HASH_BLAKE2S #define BOOTLOADER_IMAGE_MAXSIZE (128 * 1024 * 1) // 128 KB #define FIRMWARE_IMAGE_MAXSIZE (128 * 1024 * 13) // 1664 KB #define NORCOW_SECTOR_SIZE (64 * 1024) diff --git a/core/embed/models/model_T2T1.h b/core/embed/models/model_T2T1.h index 5a98e7cafbf..4c74521485e 100644 --- a/core/embed/models/model_T2T1.h +++ b/core/embed/models/model_T2T1.h @@ -19,10 +19,12 @@ (const uint8_t *)"\xb8\x30\x7a\x71\xf5\x52\xc6\x0a\x4c\xbb\x31\x7f\xf4\x8b\x82\xcd\xbf\x6b\x6b\xb5\xf0\x4c\x92\x0f\xec\x7b\xad\xf0\x17\x88\x37\x51", #define BOARDLOADER_START 0x08000000 +#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOOTLOADER_START 0x08020000 #define FIRMWARE_START 0x08040000 #define IMAGE_CHUNK_SIZE (128 * 1024) +#define IMAGE_HASH_BLAKE2S #define BOOTLOADER_IMAGE_MAXSIZE (128 * 1024 * 1) // 128 KB #define FIRMWARE_IMAGE_MAXSIZE (128 * 1024 * 13) // 1664 KB #define NORCOW_SECTOR_SIZE (64 * 1024) diff --git a/core/embed/models/model_T3T1.h b/core/embed/models/model_T3T1.h new file mode 100644 index 00000000000..e4f7241a54a --- /dev/null +++ b/core/embed/models/model_T3T1.h @@ -0,0 +1,34 @@ +#ifndef MODELS_MODEL_T3T1_H_ +#define MODELS_MODEL_T3T1_H_ + +#include "sizedefs.h" + +#define MODEL_NAME "T3T1" +#define MODEL_FULL_NAME "Trezor T3T1" +#define MODEL_INTERNAL_NAME "T3T1" +#define MODEL_INTERNAL_NAME_TOKEN T3T1 +#define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T3T1 + +/*** Using DEV KEYS temporarily ***/ +#define MODEL_BOARDLOADER_KEYS \ + (const uint8_t *)"\xdb\x99\x5f\xe2\x51\x69\xd1\x41\xca\xb9\xbb\xba\x92\xba\xa0\x1f\x9f\x2e\x1e\xce\x7d\xf4\xcb\x2a\xc0\x51\x90\xf3\x7f\xcc\x1f\x9d", \ + (const uint8_t *)"\x21\x52\xf8\xd1\x9b\x79\x1d\x24\x45\x32\x42\xe1\x5f\x2e\xab\x6c\xb7\xcf\xfa\x7b\x6a\x5e\xd3\x00\x97\x96\x0e\x06\x98\x81\xdb\x12", \ + (const uint8_t *)"\x22\xfc\x29\x77\x92\xf0\xb6\xff\xc0\xbf\xcf\xdb\x7e\xdb\x0c\x0a\xa1\x4e\x02\x5a\x36\x5e\xc0\xe3\x42\xe8\x6e\x38\x29\xcb\x74\xb6", + +#define MODEL_BOOTLOADER_KEYS \ + (const uint8_t *)"\xd7\x59\x79\x3b\xbc\x13\xa2\x81\x9a\x82\x7c\x76\xad\xb6\xfb\xa8\xa4\x9a\xee\x00\x7f\x49\xf2\xd0\x99\x2d\x99\xb8\x25\xad\x2c\x48", \ + (const uint8_t *)"\x63\x55\x69\x1c\x17\x8a\x8f\xf9\x10\x07\xa7\x47\x8a\xfb\x95\x5e\xf7\x35\x2c\x63\xe7\xb2\x57\x03\x98\x4c\xf7\x8b\x26\xe2\x1a\x56", \ + (const uint8_t *)"\xee\x93\xa4\xf6\x6f\x8d\x16\xb8\x19\xbb\x9b\xeb\x9f\xfc\xcd\xfc\xdc\x14\x12\xe8\x7f\xee\x6a\x32\x4c\x2a\x99\xa1\xe0\xe6\x71\x48", + +#define BOARDLOADER_START 0x0C004000 +#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define BOOTLOADER_START 0x0C010000 +#define FIRMWARE_START 0x0C050000 + +#define IMAGE_CHUNK_SIZE (128 * 1024) +#define IMAGE_HASH_SHA256 +#define BOOTLOADER_IMAGE_MAXSIZE (128 * 1024 * 1) // 128 KB +#define FIRMWARE_IMAGE_MAXSIZE (128 * 1024 * 13) // 1664 KB +#define NORCOW_SECTOR_SIZE (64 * 1024) + +#endif diff --git a/core/embed/models/model_T3T1_layout.c b/core/embed/models/model_T3T1_layout.c new file mode 100644 index 00000000000..9e3cd82d3f3 --- /dev/null +++ b/core/embed/models/model_T3T1_layout.c @@ -0,0 +1,93 @@ +#include "flash.h" +#include "model.h" + +const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = { + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x18, + .num_sectors = 8, + }, + }, + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x20, + .num_sectors = 8, + }, + }, +}; + +const flash_area_t BOARDLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 2, + .num_sectors = 6, + }, +}; + +const flash_area_t BOOTLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x08, + .num_sectors = 16, + }, +}; + +const flash_area_t FIRMWARE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x28, + .num_sectors = 208, + }, +}; + +const flash_area_t SECRET_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0, + .num_sectors = 2, + }, +}; + +const flash_area_t BHK_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 1, + .num_sectors = 1, + }, +}; + +const flash_area_t TRANSLATIONS_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 248, + .num_sectors = 8, + }, +}; + +const flash_area_t WIPE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x18, + .num_sectors = 232, + }, +}; + +const flash_area_t ALL_WIPE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0x08, + .num_sectors = 248, + }, +}; diff --git a/core/embed/prodtest/.changelog.d/3370.added b/core/embed/prodtest/.changelog.d/3370.added new file mode 100644 index 00000000000..20f7c864664 --- /dev/null +++ b/core/embed/prodtest/.changelog.d/3370.added @@ -0,0 +1 @@ +Added basic support for STM32U5 diff --git a/core/embed/prodtest/README.md b/core/embed/prodtest/README.md index 90e3c28d440..35afc352b8a 100644 --- a/core/embed/prodtest/README.md +++ b/core/embed/prodtest/README.md @@ -160,6 +160,21 @@ SBU 1 0 OK ``` + +### HAPTIC +The `HAPTIC` command allows you to test the functionality of the device's haptic driver. +It takes one input parameter, representing the duration of the vibration in milliseconds. +The device only vibrates if there is motor connected to the haptic driver, otherwise the effect needs to be +measured by an oscilloscope. + +Example: +``` +// runs the driver for 3000 ms + +HAPTIC 3000 +OK +``` + ### OTP READ The `OTP READ` command is utilized to retrieve a string parameter from the device's OTP memory. This string typically contains information identifying the model and production batch of the device. diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index a9416624dd2..331173a7408 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -27,7 +27,9 @@ #include "common.h" #include "display.h" #include "display_utils.h" +#include "fault_handlers.h" #include "flash.h" +#include "flash_otp.h" #include "i2c.h" #include "model.h" #include "mpu.h" @@ -46,13 +48,26 @@ #include "optiga_transport.h" #endif +#ifdef USE_HAPTIC +#include "haptic.h" +#endif + +#ifdef USE_HASH_PROCESSOR +#include "hash_processor.h" +#endif + #include "memzero.h" + +#ifdef STM32U5 +#include "stm32u5xx_ll_utils.h" +#else #include "stm32f4xx_ll_utils.h" +#endif #ifdef TREZOR_MODEL_T #define MODEL_IDENTIFIER "TREZOR2-" -#elif TREZOR_MODEL_R -#define MODEL_IDENTIFIER "T2B1-" +#else +#define MODEL_IDENTIFIER MODEL_INTERNAL_NAME "-" #endif static secbool startswith(const char *s, const char *prefix) { @@ -427,10 +442,10 @@ static void test_sd(void) { static void test_wipe(void) { // erase start of the firmware (metadata) -> invalidate FW ensure(flash_unlock_write(), NULL); - for (int i = 0; i < 1024 / sizeof(uint32_t); i++) { - ensure( - flash_area_write_word(&FIRMWARE_AREA, i * sizeof(uint32_t), 0x00000000), - NULL); + for (int i = 0; i < (1024 / FLASH_BLOCK_SIZE); i += FLASH_BLOCK_SIZE) { + flash_block_t data = {0}; + ensure(flash_area_write_block(&FIRMWARE_AREA, i * FLASH_BLOCK_SIZE, data), + NULL); } ensure(flash_lock_write(), NULL); display_clear(); @@ -449,6 +464,24 @@ static void test_sbu(const char *args) { } #endif +#ifdef USE_HAPTIC +static void test_haptic(const char *args) { + int duration_ms = atoi(args); + + if (duration_ms <= 0) { + vcp_println("ERROR HAPTIC DURATION"); + return; + } + + if (haptic_test(duration_ms)) { + vcp_println("OK"); + + } else { + vcp_println("ERROR HAPTIC"); + } +} +#endif + static void test_otp_read(void) { uint8_t data[32]; memzero(data, sizeof(data)); @@ -546,6 +579,9 @@ int main(void) { display_reinit(); display_orientation(0); random_delays_init(); +#ifdef USE_HASH_PROCESSOR + hash_processor_init(); +#endif #ifdef USE_SD_CARD sdcard_init(); #endif @@ -560,9 +596,14 @@ int main(void) { #endif #ifdef USE_SBU sbu_init(); +#endif +#ifdef USE_HAPTIC + haptic_init(); #endif usb_init_all(); + mpu_config_prodtest_initial(); + #ifdef USE_OPTIGA optiga_init(); optiga_open_application(); @@ -570,13 +611,15 @@ int main(void) { #endif mpu_config_prodtest(); + fault_handlers_init(); + drop_privileges(); display_clear(); draw_welcome_screen(); char dom[32]; - // format: TREZOR2-YYMMDD + // format: {MODEL_IDENTIFIER}-YYMMDD if (sectrue == flash_otp_read(FLASH_OTP_BLOCK_BATCH, 0, (uint8_t *)dom, 32) && sectrue == startswith(dom, MODEL_IDENTIFIER) && dom[31] == 0) { display_qrcode(DISPLAY_RESX / 2, DISPLAY_RESY / 2, dom, 4); @@ -624,6 +667,10 @@ int main(void) { } else if (startswith(line, "SBU ")) { test_sbu(line + 4); #endif +#ifdef USE_HAPTIC + } else if (startswith(line, "HAPTIC ")) { + test_haptic(line + 7); +#endif #ifdef USE_OPTIGA } else if (startswith(line, "OPTIGAID READ")) { optigaid_read(); @@ -669,5 +716,3 @@ int main(void) { return 0; } - -void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR!", "(HF)"); } diff --git a/core/embed/prodtest/memory.ld b/core/embed/prodtest/memory_stm32f4.ld similarity index 95% rename from core/embed/prodtest/memory.ld rename to core/embed/prodtest/memory_stm32f4.ld index afbe0aa3bb1..61f7112ba83 100644 --- a/core/embed/prodtest/memory.ld +++ b/core/embed/prodtest/memory_stm32f4.ld @@ -10,6 +10,7 @@ MEMORY { } main_stack_base = ORIGIN(SRAM) + LENGTH(SRAM); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM); _estack = main_stack_base; /* used by the startup code to populate variables used by the C code */ @@ -73,4 +74,9 @@ SECTIONS { .stack : ALIGN(8) { . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ } >SRAM + + .boot_args : ALIGN(8) { + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS } diff --git a/core/embed/prodtest/memory_stm32u58.ld b/core/embed/prodtest/memory_stm32u58.ld new file mode 100644 index 00000000000..54795edb71e --- /dev/null +++ b/core/embed/prodtest/memory_stm32u58.ld @@ -0,0 +1,121 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K + SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM1 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram1_end); /* this explicitly sets the end of the heap */ + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/prodtest/memory_stm32u5a.ld b/core/embed/prodtest/memory_stm32u5a.ld new file mode 100644 index 00000000000..f5aee9ae357 --- /dev/null +++ b/core/embed/prodtest/memory_stm32u5a.ld @@ -0,0 +1,127 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 0 + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM1 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram1_end); /* this explicitly sets the end of the heap */ + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/prodtest/optiga_prodtest.c b/core/embed/prodtest/optiga_prodtest.c index 78943aa81e8..87e45317efc 100644 --- a/core/embed/prodtest/optiga_prodtest.c +++ b/core/embed/prodtest/optiga_prodtest.c @@ -126,35 +126,40 @@ void pair_optiga(void) { // pairing procedure is determined by optiga_sec_chan_handshake(). Therefore // it is OK for some of the intermediate operations to fail. - // Enable writing the pairing secret to OPTIGA. - optiga_metadata metadata = {0}; - metadata.change = OPTIGA_META_ACCESS_ALWAYS; - metadata.execute = OPTIGA_META_ACCESS_ALWAYS; - metadata.data_type = TYPE_PTFBIND; - set_metadata(OID_KEY_PAIRING, &metadata); // Ignore result. - - // Generate pairing secret. uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; - optiga_result ret = optiga_get_random(secret, sizeof(secret)); - if (OPTIGA_SUCCESS != ret) { - optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG; - return; - } + optiga_result ret = OPTIGA_SUCCESS; + + if (secret_optiga_extract(secret) != sectrue) { + // Enable writing the pairing secret to OPTIGA. + optiga_metadata metadata = {0}; + metadata.change = OPTIGA_META_ACCESS_ALWAYS; + metadata.execute = OPTIGA_META_ACCESS_ALWAYS; + metadata.data_type = TYPE_PTFBIND; + set_metadata(OID_KEY_PAIRING, &metadata); // Ignore result. + + // Generate pairing secret. + ret = optiga_get_random(secret, sizeof(secret)); + if (OPTIGA_SUCCESS != ret) { + optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG; + return; + } - // Store pairing secret. - ret = optiga_set_data_object(OID_KEY_PAIRING, false, secret, sizeof(secret)); - if (OPTIGA_SUCCESS == ret) { - secret_erase(); - secret_write_header(); - secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); - } + // Store pairing secret. + ret = + optiga_set_data_object(OID_KEY_PAIRING, false, secret, sizeof(secret)); + if (OPTIGA_SUCCESS == ret) { + secret_erase(); + secret_write_header(); + secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); + } - // Verify whether the secret was stored correctly in flash and OPTIGA. - memzero(secret, sizeof(secret)); - if (secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN) != - sectrue) { - optiga_pairing_state = OPTIGA_PAIRING_ERR_READ; - return; + // Verify whether the secret was stored correctly in flash and OPTIGA. + memzero(secret, sizeof(secret)); + if (secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN) != + sectrue) { + optiga_pairing_state = OPTIGA_PAIRING_ERR_READ; + return; + } } ret = optiga_sec_chan_handshake(secret, sizeof(secret)); diff --git a/core/embed/prodtest/startup.s b/core/embed/prodtest/startup_stm32f4.s similarity index 100% rename from core/embed/prodtest/startup.s rename to core/embed/prodtest/startup_stm32f4.s diff --git a/core/embed/prodtest/startup_stm32u5.s b/core/embed/prodtest/startup_stm32u5.s new file mode 100644 index 00000000000..19e183adcf0 --- /dev/null +++ b/core/embed/prodtest/startup_stm32u5.s @@ -0,0 +1,72 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #16 // padding + msr MSPLIM, r0 + + // setup environment for subsequent stage of code + ldr r2, =0 // r2 - the word-sized value to be written + + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + // copy data in from flash + ldr r0, =data_vma // dst addr + ldr r1, =data_lma // src addr + ldr r2, =data_size // size in bytes + bl memcpy + + // copy sensitive data in from flash + ldr r0, =sensitive_vma // dst addr + ldr r1, =sensitive_lma // src addr + ldr r2, =sensitive_size // size in bytes + bl memcpy + + // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value + bl rng_get + ldr r1, = __stack_chk_guard + str r0, [r1] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/reflash/main.c b/core/embed/reflash/main.c index d1f266d62ee..1c00bf336ea 100644 --- a/core/embed/reflash/main.c +++ b/core/embed/reflash/main.c @@ -34,6 +34,10 @@ #include "secbool.h" #include "touch.h" +#ifdef USE_HASH_PROCESSOR +#include "hash_processor.h" +#endif + static void progress_callback(int pos, int len) { term_printf("."); } static void flash_from_sdcard(const flash_area_t* area, uint32_t source, @@ -66,6 +70,10 @@ int main(void) { sdcard_init(); touch_init(); +#ifdef USE_HASH_PROCESSOR + hash_processor_init(); +#endif + display_orientation(0); display_clear(); display_backlight(255); diff --git a/core/embed/reflash/memory.ld b/core/embed/reflash/memory_stm32f4.ld similarity index 96% rename from core/embed/reflash/memory.ld rename to core/embed/reflash/memory_stm32f4.ld index 89b38a8bac0..718b009385a 100644 --- a/core/embed/reflash/memory.ld +++ b/core/embed/reflash/memory_stm32f4.ld @@ -73,4 +73,9 @@ SECTIONS { .stack : ALIGN(8) { . = 4K; /* this acts as a build time assertion that at least this much memory is available for stack use */ } >SRAM + + .boot_args : ALIGN(8) { + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS } diff --git a/core/embed/reflash/memory_stm32u58.ld b/core/embed/reflash/memory_stm32u58.ld new file mode 100644 index 00000000000..a632e270c27 --- /dev/null +++ b/core/embed/reflash/memory_stm32u58.ld @@ -0,0 +1,122 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 192K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x3002FF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x30030000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x30040000, LENGTH = 512K + SRAM5 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM5 is not available */ + SRAM6 (wal) : ORIGIN = 0x30080000, LENGTH = 0K /* SRAM6 is not available */ + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM1 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram1_end); /* this explicitly sets the end of the heap */ + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K + 0x100; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM3 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/reflash/memory_stm32u5a.ld b/core/embed/reflash/memory_stm32u5a.ld new file mode 100644 index 00000000000..bcd7458cc6e --- /dev/null +++ b/core/embed/reflash/memory_stm32u5a.ld @@ -0,0 +1,128 @@ +/* TREZORv2 firmware linker script */ + +ENTRY(reset_handler) + +MEMORY { + FLASH (rx) : ORIGIN = 0x0C050000, LENGTH = 3648K + SRAM1 (wal) : ORIGIN = 0x30000000, LENGTH = 768K - 0x100 + BOOT_ARGS (wal) : ORIGIN = 0x300BFF00, LENGTH = 0x100 + SRAM2 (wal) : ORIGIN = 0x300C0000, LENGTH = 64K + SRAM3 (wal) : ORIGIN = 0x300D0000, LENGTH = 832K + SRAM5 (wal) : ORIGIN = 0x301A0000, LENGTH = 832K + SRAM6 (wal) : ORIGIN = 0x30270000, LENGTH = 512K + SRAM4 (wal) : ORIGIN = 0x38000000, LENGTH = 16K +} + +main_stack_base = ORIGIN(SRAM2) + SIZEOF(.stack); /* 8-byte aligned full descending stack */ +_sstack = ORIGIN(SRAM2); +_estack = main_stack_base; + +/* used by the startup code to populate variables used by the C code */ +data_lma = LOADADDR(.data); +data_vma = ADDR(.data); +data_size = SIZEOF(.data); + +/* used by the startup code to populate variables used by the C code */ +sensitive_lma = LOADADDR(.sensitive); +sensitive_vma = ADDR(.sensitive); +sensitive_size = SIZEOF(.sensitive); + +/* used by the startup code to wipe memory */ +sram1_start = ORIGIN(SRAM1); +sram1_end = ORIGIN(SRAM1) + LENGTH(SRAM1); +sram2_start = ORIGIN(SRAM2); +sram2_end = ORIGIN(SRAM2) + LENGTH(SRAM2); +sram3_start = ORIGIN(SRAM3); +sram3_end = ORIGIN(SRAM3) + LENGTH(SRAM3); +sram4_start = ORIGIN(SRAM4); +sram4_end = ORIGIN(SRAM4) + LENGTH(SRAM4); +sram5_start = ORIGIN(SRAM5); +sram5_end = ORIGIN(SRAM5) + LENGTH(SRAM5); +sram6_start = ORIGIN(SRAM6); +sram6_end = ORIGIN(SRAM6) + LENGTH(SRAM6); + +/* reserve 256 bytes for bootloader arguments */ +boot_args_start = ORIGIN(BOOT_ARGS); +boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); + +_codelen = SIZEOF(.flash) + SIZEOF(.data) + SIZEOF(.sensitive); +_flash_start = ORIGIN(FLASH); +_flash_end = ORIGIN(FLASH) + LENGTH(FLASH); +_heap_start = ADDR(.heap); +_heap_end = ADDR(.heap) + SIZEOF(.heap); + +SECTIONS { + .vendorheader : ALIGN(4) { + KEEP(*(.vendorheader)) + } >FLASH AT>FLASH + + .header : ALIGN(4) { + KEEP(*(.header)); + } >FLASH AT>FLASH + + .flash : ALIGN(512) { + KEEP(*(.vector_table)); + . = ALIGN(4); + *(.text*); + . = ALIGN(4); + *(.rodata*); + . = ALIGN(4); + KEEP(*(.bootloader)); + *(.bootloader*); + . = ALIGN(512); + } >FLASH AT>FLASH + + .data : ALIGN(4) { + *(.data*); + . = ALIGN(512); + } >SRAM1 AT>FLASH + + /DISCARD/ : { + *(.ARM.exidx*); + } + + .bss : ALIGN(4) { + *(.bss*); + . = ALIGN(4); + } >SRAM1 + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >SRAM1 + + .heap : ALIGN(4) { + . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ + . = ABSOLUTE(sram1_end); /* this explicitly sets the end of the heap */ + } >SRAM1 + + .stack : ALIGN(8) { + . = 16K + 0x100; /* Overflow causes UsageFault */ + } >SRAM2 + + .sensitive : ALIGN(512) { + *(.sensitive*); + . = ALIGN(512); + } >SRAM2 AT>FLASH + + .fb1 : ALIGN(4) { + __fb_start = .; + *(.fb1*); + *(.gfxmmu_table*); + *(.framebuffer_select*); + . = ALIGN(4); + } >SRAM3 + + .fb2 : ALIGN(4) { + *(.fb2*); + __fb_end = .; + . = ALIGN(4); + } >SRAM5 + + .boot_args : ALIGN(8) { + *(.boot_command*); + . = ALIGN(8); + *(.boot_args*); + . = ALIGN(8); + } >BOOT_ARGS +} diff --git a/core/embed/reflash/startup.s b/core/embed/reflash/startup_stm32f4.s similarity index 100% rename from core/embed/reflash/startup.s rename to core/embed/reflash/startup_stm32f4.s diff --git a/core/embed/reflash/startup_stm32u5.s b/core/embed/reflash/startup_stm32u5.s new file mode 100644 index 00000000000..19e183adcf0 --- /dev/null +++ b/core/embed/reflash/startup_stm32u5.s @@ -0,0 +1,72 @@ + .syntax unified + + .text + + .global reset_handler + .type reset_handler, STT_FUNC +reset_handler: + // set the stack protection + ldr r0, =_sstack + add r0, r0, #16 // padding + msr MSPLIM, r0 + + // setup environment for subsequent stage of code + ldr r2, =0 // r2 - the word-sized value to be written + + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + // copy data in from flash + ldr r0, =data_vma // dst addr + ldr r1, =data_lma // src addr + ldr r2, =data_size // size in bytes + bl memcpy + + // copy sensitive data in from flash + ldr r0, =sensitive_vma // dst addr + ldr r1, =sensitive_lma // src addr + ldr r2, =sensitive_size // size in bytes + bl memcpy + + // setup the stack protector (see build script "-fstack-protector-all") with an unpredictable value + bl rng_get + ldr r1, = __stack_chk_guard + str r0, [r1] + + // re-enable exceptions + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.7: + // "If it is not necessary to ensure that a pended interrupt is recognized immediately before + // subsequent operations, it is not necessary to insert a memory barrier instruction." + cpsie f + + // enter the application code + bl main + + b shutdown_privileged + + .end diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml index bd9ead0b1e3..93b23a5c8a7 100644 --- a/core/embed/rust/Cargo.toml +++ b/core/embed/rust/Cargo.toml @@ -28,6 +28,7 @@ disp_i8080_8bit_dw = [] # write pixels directly to peripheral disp_i8080_16bit_dw = [] # write pixels directly to peripheral debug = ["ui_debug"] sbu = [] +haptic = [] sd_card = [] rgb_led = [] backlight = [] diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index 5363c028ce1..4bf8f574bc3 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -123,7 +123,6 @@ fn prepare_bindings() -> bindgen::Builder { clang_args.push("-nostdinc"); clang_args.push("-I../firmware"); clang_args.push("-I../../build/firmware"); - clang_args.push("-I../../vendor/micropython/lib/cmsis/inc"); clang_args.push("-DUSE_HAL_DRIVER"); bindings = bindings.clang_args(&clang_args); @@ -405,7 +404,10 @@ fn generate_trezorhal_bindings() { // touch .allowlist_function("touch_read") // button - .allowlist_function("button_read"); + .allowlist_function("button_read") + // haptic + .allowlist_type("haptic_effect_t") + .allowlist_function("haptic_play"); // Write the bindings to a file in the OUR_DIR. bindings @@ -448,7 +450,7 @@ fn generate_crypto_bindings() { fn is_firmware() -> bool { let target = env::var("TARGET").unwrap(); - target.starts_with("thumbv7") + target.starts_with("thumbv7") || target.starts_with("thumbv8") } #[cfg(feature = "test")] diff --git a/core/embed/rust/src/trezorhal/haptic.rs b/core/embed/rust/src/trezorhal/haptic.rs new file mode 100644 index 00000000000..d76474c2b38 --- /dev/null +++ b/core/embed/rust/src/trezorhal/haptic.rs @@ -0,0 +1,13 @@ +use super::ffi; + +#[derive(PartialEq, Debug, Eq, FromPrimitive, Clone, Copy)] +pub enum HapticEffect { + ButtonPress = ffi::haptic_effect_t_HAPTIC_BUTTON_PRESS as _, + HoldToConfirm = ffi::haptic_effect_t_HAPTIC_HOLD_TO_CONFIRM as _, +} + +pub fn play(effect: HapticEffect) { + unsafe { + ffi::haptic_play(effect as _); + } +} diff --git a/core/embed/rust/src/trezorhal/mod.rs b/core/embed/rust/src/trezorhal/mod.rs index 1aea7bb35a0..39de9515106 100644 --- a/core/embed/rust/src/trezorhal/mod.rs +++ b/core/embed/rust/src/trezorhal/mod.rs @@ -7,6 +7,8 @@ pub mod display; #[cfg(feature = "dma2d")] pub mod dma2d; mod ffi; +#[cfg(feature = "haptic")] +pub mod haptic; pub mod io; pub mod model; pub mod random; diff --git a/core/embed/rust/src/ui/model_tt/component/button.rs b/core/embed/rust/src/ui/model_tt/component/button.rs index 4a319070ea0..d9e2a558c20 100644 --- a/core/embed/rust/src/ui/model_tt/component/button.rs +++ b/core/embed/rust/src/ui/model_tt/component/button.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "haptic")] +use crate::trezorhal::haptic::{play, HapticEffect}; use crate::{ time::Duration, ui::{ @@ -256,6 +258,8 @@ where _ => { // Touch started in our area, transform to `Pressed` state. if touch_area.contains(pos) { + #[cfg(feature = "haptic")] + play(HapticEffect::ButtonPress); self.set(ctx, State::Pressed); if let Some(duration) = self.long_press { self.long_timer = Some(ctx.request_timer(duration)); @@ -298,6 +302,8 @@ where if self.long_timer == Some(token) { self.long_timer = None; if matches!(self.state, State::Pressed) { + #[cfg(feature = "haptic")] + play(HapticEffect::ButtonPress); self.set(ctx, State::Initial); return Some(ButtonMsg::LongPressed); } diff --git a/core/embed/rust/src/ui/model_tt/component/loader.rs b/core/embed/rust/src/ui/model_tt/component/loader.rs index d661653b711..ebac3b3aacd 100644 --- a/core/embed/rust/src/ui/model_tt/component/loader.rs +++ b/core/embed/rust/src/ui/model_tt/component/loader.rs @@ -1,3 +1,5 @@ +#[cfg(feature = "haptic")] +use crate::trezorhal::haptic::{play, HapticEffect}; use crate::{ time::{Duration, Instant}, ui::{ @@ -165,6 +167,8 @@ impl Component for Loader { } if self.is_completely_grown(now) { + #[cfg(feature = "haptic")] + play(HapticEffect::HoldToConfirm); return Some(LoaderMsg::GrownCompletely); } else if self.is_completely_shrunk(now) { return Some(LoaderMsg::ShrunkCompletely); diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h index fd64ba5b84b..1ee7ac69a7b 100644 --- a/core/embed/rust/trezorhal.h +++ b/core/embed/rust/trezorhal.h @@ -7,6 +7,7 @@ #include "dma2d.h" #include "flash.h" #include "fonts/fonts.h" +#include "haptic.h" #include "model.h" #include "rgb_led.h" #include "secbool.h" diff --git a/core/embed/trezorhal/board_capabilities.h b/core/embed/trezorhal/board_capabilities.h index b6e7b7befe0..e7465960b0e 100644 --- a/core/embed/trezorhal/board_capabilities.h +++ b/core/embed/trezorhal/board_capabilities.h @@ -35,7 +35,6 @@ Last tag must be terminator or all space used. #include -#define BOARD_CAPABILITIES_ADDR 0x0800BF00 #define BOARD_CAPABILITIES_SIZE 256 #define CAPABILITIES_HEADER "TRZC" diff --git a/core/embed/trezorhal/boards/board-unix.h b/core/embed/trezorhal/boards/board-unix.h index ec16dd4ad5a..bdc7acf73da 100644 --- a/core/embed/trezorhal/boards/board-unix.h +++ b/core/embed/trezorhal/boards/board-unix.h @@ -9,6 +9,13 @@ #define USE_BACKLIGHT 1 #endif +#ifdef TREZOR_MODEL_T3T1 +#define USE_TOUCH 1 +#define USE_SD_CARD 1 +#define USE_SBU 1 +#define USE_RGB_COLORS 1 +#endif + #ifdef TREZOR_MODEL_1 #define USE_BUTTON 1 #endif diff --git a/core/embed/trezorhal/boards/stm32f429i-disc1.h b/core/embed/trezorhal/boards/stm32f429i-disc1.h index a12ad1a0569..9f8b0a65ec0 100644 --- a/core/embed/trezorhal/boards/stm32f429i-disc1.h +++ b/core/embed/trezorhal/boards/stm32f429i-disc1.h @@ -16,18 +16,18 @@ #include "displays/ltdc.h" #define I2C_COUNT 1 -#define I2C_INSTANCE_1 I2C3 -#define I2C_INSTANCE_1_CLK_EN __HAL_RCC_I2C3_CLK_ENABLE -#define I2C_INSTANCE_1_CLK_DIS __HAL_RCC_I2C3_CLK_DISABLE -#define I2C_INSTANCE_1_PIN_AF GPIO_AF4_I2C3 -#define I2C_INSTANCE_1_SDA_PORT GPIOC -#define I2C_INSTANCE_1_SDA_PIN GPIO_PIN_9 -#define I2C_INSTANCE_1_SDA_CLK_EN __HAL_RCC_GPIOC_CLK_ENABLE -#define I2C_INSTANCE_1_SCL_PORT GPIOA -#define I2C_INSTANCE_1_SCL_PIN GPIO_PIN_8 -#define I2C_INSTANCE_1_SCL_CLK_EN __HAL_RCC_GPIOA_CLK_ENABLE -#define I2C_INSTANCE_1_RESET_FLG RCC_APB1RSTR_I2C3RST +#define I2C_INSTANCE_0 I2C3 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C3_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C3_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF4_I2C3 +#define I2C_INSTANCE_0_SDA_PORT GPIOC +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_9 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOC_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOA +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_8 +#define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOA_CLK_ENABLE +#define I2C_INSTANCE_0_RESET_FLG RCC_APB1RSTR_I2C3RST -#define TOUCH_I2C_NUM 0 +#define TOUCH_I2C_INSTANCE 0 #endif //_STM32F429I_DISC1_H diff --git a/core/embed/trezorhal/boards/stm32u5a9j-dk.h b/core/embed/trezorhal/boards/stm32u5a9j-dk.h new file mode 100644 index 00000000000..3ff3673ee61 --- /dev/null +++ b/core/embed/trezorhal/boards/stm32u5a9j-dk.h @@ -0,0 +1,32 @@ +#ifndef STM32U5A9J_DK_H_ +#define STM32U5A9J_DK_H_ + +#define HSE_16MHZ +#define VDD_1V8 1 + +#define USE_I2C 1 +#define USE_RGB_COLORS 1 +#define USE_TOUCH 1 +//#define USE_SBU 1 +//#define USE_DISP_I8080_8BIT_DW 1 +#define USE_HASH_PROCESSOR 1 + +#include "displays/dsi.h" + +#define I2C_COUNT 1 +#define I2C_INSTANCE_0 I2C5 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C5_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C5_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF2_I2C5 +#define I2C_INSTANCE_0_SDA_PORT GPIOH +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_4 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOH_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOH +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_5 +#define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOH_CLK_ENABLE +#define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR2 +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR2_I2C5RST + +#define TOUCH_I2C_INSTANCE 0 + +#endif // STM32U5A9J_DK_H_ diff --git a/core/embed/trezorhal/boards/trezor_r_v10.h b/core/embed/trezorhal/boards/trezor_r_v10.h index e20b4a014c2..be44e5585dd 100644 --- a/core/embed/trezorhal/boards/trezor_r_v10.h +++ b/core/embed/trezorhal/boards/trezor_r_v10.h @@ -38,18 +38,21 @@ #define OLED_SPI_MOSI_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE #define I2C_COUNT 1 -#define I2C_INSTANCE_1 I2C2 -#define I2C_INSTANCE_1_CLK_EN __HAL_RCC_I2C2_CLK_ENABLE -#define I2C_INSTANCE_1_CLK_DIS __HAL_RCC_I2C2_CLK_DISABLE -#define I2C_INSTANCE_1_PIN_AF GPIO_AF4_I2C2 -#define I2C_INSTANCE_1_SDA_PORT GPIOB -#define I2C_INSTANCE_1_SDA_PIN GPIO_PIN_11 -#define I2C_INSTANCE_1_SDA_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE -#define I2C_INSTANCE_1_SCL_PORT GPIOB -#define I2C_INSTANCE_1_SCL_PIN GPIO_PIN_10 -#define I2C_INSTANCE_1_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE -#define I2C_INSTANCE_1_RESET_FLG RCC_APB1RSTR_I2C2RST +#define I2C_INSTANCE_0 I2C2 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C2_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C2_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF4_I2C2 +#define I2C_INSTANCE_0_SDA_PORT GPIOB +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_11 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOB +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_10 +#define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_RESET_FLG RCC_APB1RSTR_I2C2RST #define OPTIGA_I2C_INSTANCE 0 +#define OPTIGA_RST_PORT GPIOD +#define OPTIGA_RST_PIN GPIO_PIN_9 +#define OPTIGA_RST_CLK_EN __HAL_RCC_GPIOD_CLK_ENABLE #endif //_TREZOR_R_V10_H diff --git a/core/embed/trezorhal/boards/trezor_t.h b/core/embed/trezorhal/boards/trezor_t.h index 8d6c8ba2de1..557f8bb55c6 100644 --- a/core/embed/trezorhal/boards/trezor_t.h +++ b/core/embed/trezorhal/boards/trezor_t.h @@ -33,20 +33,20 @@ #define BACKLIGHT_PWM_PORT_CLK_EN __HAL_RCC_GPIOA_CLK_ENABLE #define I2C_COUNT 1 -#define I2C_INSTANCE_1 I2C1 -#define I2C_INSTANCE_1_CLK_EN __HAL_RCC_I2C1_CLK_ENABLE -#define I2C_INSTANCE_1_CLK_DIS __HAL_RCC_I2C1_CLK_DISABLE -#define I2C_INSTANCE_1_PIN_AF GPIO_AF4_I2C1 -#define I2C_INSTANCE_1_SDA_PORT GPIOB -#define I2C_INSTANCE_1_SDA_PIN GPIO_PIN_7 -#define I2C_INSTANCE_1_SDA_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE -#define I2C_INSTANCE_1_SCL_PORT GPIOB -#define I2C_INSTANCE_1_SCL_PIN GPIO_PIN_6 -#define I2C_INSTANCE_1_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE -#define I2C_INSTANCE_1_RESET_FLG RCC_APB1RSTR_I2C1RST +#define I2C_INSTANCE_0 I2C1 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C1_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C1_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF4_I2C1 +#define I2C_INSTANCE_0_SDA_PORT GPIOB +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_7 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOB +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_6 +#define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_RESET_FLG RCC_APB1RSTR_I2C1RST #define TOUCH_SENSITIVITY 0x06 -#define TOUCH_I2C_NUM 0 +#define TOUCH_I2C_INSTANCE 0 #define TOUCH_RST_PORT GPIOC #define TOUCH_RST_PIN GPIO_PIN_5 #define TOUCH_INT_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_t3t1_v4.h b/core/embed/trezorhal/boards/trezor_t3t1_v4.h new file mode 100644 index 00000000000..cf4ea3fa40c --- /dev/null +++ b/core/embed/trezorhal/boards/trezor_t3t1_v4.h @@ -0,0 +1,90 @@ +#ifndef _TREZOR_T3T1_H +#define _TREZOR_T3T1_H + +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 + +#define VDD_1V8 1 +#define HSE_16MHZ 1 + +#define USE_SD_CARD 1 +#define USE_I2C 1 +#define USE_TOUCH 1 +#define USE_SBU 1 +#define USE_RGB_COLORS 1 +#define USE_DISP_I8080_8BIT_DW 1 +#define USE_HAPTIC 1 +#define USE_BACKLIGHT 1 +#define USE_HASH_PROCESSOR 1 + +#include "displays/panels/lx154a2422.h" +#include "displays/st7789v.h" +#define DISPLAY_IDENTIFY 1 +#define DISPLAY_TE_PORT GPIOD +#define DISPLAY_TE_PIN GPIO_PIN_12 + +#define DISPLAY_PANEL_INIT_SEQ lx154a2422_init_seq +#define DISPLAY_PANEL_ROTATE lx154a2422_rotate +#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords + +#define BACKLIGHT_PWM_FREQ 12500 +#define BACKLIGHT_PWM_TIM TIM8 +#define BACKLIGHT_PWM_TIM_CLK_EN __HAL_RCC_TIM8_CLK_ENABLE +#define BACKLIGHT_PWM_TIM_AF GPIO_AF3_TIM8 +#define BACKLIGHT_PWM_TIM_OCMODE TIM_OCMODE_PWM1 +#define BACKLIGHT_PWM_TIM_CHANNEL TIM_CHANNEL_1 +#define BACKLIGHT_PWM_TIM_CCR CCR1 +#define BACKLIGHT_PWM_PIN GPIO_PIN_6 +#define BACKLIGHT_PWM_PORT GPIOC +#define BACKLIGHT_PWM_PORT_CLK_EN __HAL_RCC_GPIOC_CLK_ENABLE + +#define I2C_COUNT 2 +#define I2C_INSTANCE_0 I2C1 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C1_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C1_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF4_I2C1 +#define I2C_INSTANCE_0_SDA_PORT GPIOB +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_7 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOB +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_6 +#define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR1 +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR1_I2C1RST + +#define I2C_INSTANCE_1 I2C2 +#define I2C_INSTANCE_1_CLK_EN __HAL_RCC_I2C2_CLK_ENABLE +#define I2C_INSTANCE_1_CLK_DIS __HAL_RCC_I2C2_CLK_DISABLE +#define I2C_INSTANCE_1_PIN_AF GPIO_AF4_I2C2 +#define I2C_INSTANCE_1_SDA_PORT GPIOB +#define I2C_INSTANCE_1_SDA_PIN GPIO_PIN_14 +#define I2C_INSTANCE_1_SDA_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_1_SCL_PORT GPIOB +#define I2C_INSTANCE_1_SCL_PIN GPIO_PIN_13 +#define I2C_INSTANCE_1_SCL_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE +#define I2C_INSTANCE_1_RESET_REG &RCC->APB1RSTR1 +#define I2C_INSTANCE_1_RESET_BIT RCC_APB1RSTR1_I2C2RST + +#define TOUCH_SENSITIVITY 0x40 +#define TOUCH_I2C_INSTANCE 0 +#define TOUCH_RST_PORT GPIOC +#define TOUCH_RST_PIN GPIO_PIN_5 +#define TOUCH_INT_PORT GPIOC +#define TOUCH_INT_PIN GPIO_PIN_4 +#define TOUCH_ON_PORT GPIOB +#define TOUCH_ON_PIN GPIO_PIN_0 + +#define DRV2625_I2C_INSTANCE 1 +#define HAPTIC_ACTUATOR "actuators/vg1040003d.h" + +#define OPTIGA_I2C_INSTANCE 1 +#define OPTIGA_RST_PORT GPIOB +#define OPTIGA_RST_PIN GPIO_PIN_1 +#define OPTIGA_RST_CLK_EN __HAL_RCC_GPIOB_CLK_ENABLE + +#define SD_DETECT_PORT GPIOC +#define SD_DETECT_PIN GPIO_PIN_13 +#define SD_ENABLE_PORT GPIOC +#define SD_ENABLE_PIN GPIO_PIN_0 + +#endif //_TREZOR_T_H diff --git a/core/embed/trezorhal/boot_args.h b/core/embed/trezorhal/boot_args.h index d9ccd09e30b..4236a42ae9c 100644 --- a/core/embed/trezorhal/boot_args.h +++ b/core/embed/trezorhal/boot_args.h @@ -1,6 +1,9 @@ #ifndef TREZORHAL_BOOT_ARGS_H #define TREZORHAL_BOOT_ARGS_H +#include +#include + // Defines boot command for 'svc_reboot_to_bootloader()' function typedef enum { // Normal boot sequence @@ -11,8 +14,26 @@ typedef enum { BOOT_COMMAND_INSTALL_UPGRADE = 0xFA4A5C8D, } boot_command_t; -// Maximum size of extra arguments passed to -// 'svc_reboot_to_bootloader()' function -#define BOOT_ARGS_SIZE 256 +// Maximum size boot_args array +#define BOOT_ARGS_MAX_SIZE (256 - 8) + +typedef union { + uint8_t raw[BOOT_ARGS_MAX_SIZE]; + + // firmware header hash, BOOT_COMMAND_INSTALL_UPGRADE + uint8_t hash[32]; + +} boot_args_t; + +// Sets boot command and arguments for the next reboot +// arguments have too respect boot_args_t structure layout +// (function can be called multiple times before reboting) +void bootargs_set(boot_command_t command, const void* args, size_t args_size); + +// Returns the last boot command set by bootargs_set_command() +boot_command_t bootargs_get_command(); + +// Returns the pointer to boot arguments +const boot_args_t* bootargs_get_args(); #endif // TREZORHAL_BOOT_ARGS_H diff --git a/core/embed/trezorhal/fault_handlers.h b/core/embed/trezorhal/fault_handlers.h new file mode 100644 index 00000000000..8372135f37c --- /dev/null +++ b/core/embed/trezorhal/fault_handlers.h @@ -0,0 +1,7 @@ +#ifndef TREZORHAL_FAULT_HANDLERS_H +#define TREZORHAL_FAULT_HANDLERS_H + +// Initializes and enables fault handlers +void fault_handlers_init(void); + +#endif // TREZORHAL_FAULT_HANDLERS_H diff --git a/core/embed/trezorhal/flash.h b/core/embed/trezorhal/flash.h index 11b50f8c09f..c02a2fea9c4 100644 --- a/core/embed/trezorhal/flash.h +++ b/core/embed/trezorhal/flash.h @@ -22,50 +22,14 @@ #include #include + #include "platform.h" #include "secbool.h" -#define FLASH_OTP_NUM_BLOCKS 16 -#define FLASH_OTP_BLOCK_SIZE 32 +#include "flash_ll.h" -/** - * Flash driver interface is designed to abstract away differences between - * various MCUs used in Trezor devices. - * - * Generally, flash memory is divided into sectors. On different MCUs, sectors - * may have different sizes, and therefore, different number of sectors are used - * for a given purpose. For example, on STM32F4, the sectors are relatively - * large so we use single sector for Storage. On STM32U5, the sectors are - * smaller, so we use multiple sectors for the Storage. Storage implementation - * should not care about this, and should use flash_area_t interface to access - * the flash memory. - * - * flash_area_t represents a location in flash memory. It may be contiguous, or - * it may be composed of multiple non-contiguous subareas. - * - * flash_subarea_t represents a contiguous area in flash memory, specified by - * first_sector and num_sectors. - */ - -#include "flash_common.h" +#define FLASH_BURST_LENGTH (4 * 8) void flash_init(void); -uint32_t flash_wait_and_clear_status_flags(void); - -// Erases the single sector in the designated flash area -// The 'offset' parameter must indicate the relative sector offset within the -// flash area If 'offset' is outside the bounds of the flash area, -// 'bytes_erased' is set to 0 otherwise, 'bytes_erased' is set to the size of -// the erased sector -secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset, - uint32_t *bytes_erased); - -secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, - uint8_t datalen); -secbool __wur flash_otp_write(uint8_t block, uint8_t offset, - const uint8_t *data, uint8_t datalen); -secbool __wur flash_otp_lock(uint8_t block); -secbool __wur flash_otp_is_locked(uint8_t block); - #endif // TREZORHAL_FLASH_H diff --git a/core/embed/trezorhal/flash_otp.h b/core/embed/trezorhal/flash_otp.h new file mode 100644 index 00000000000..c3f8705ab4a --- /dev/null +++ b/core/embed/trezorhal/flash_otp.h @@ -0,0 +1,18 @@ +#ifndef TREZORHAL_FLASH_OTP_H +#define TREZORHAL_FLASH_OTP_H + +#include + +#define FLASH_OTP_NUM_BLOCKS 16 +#define FLASH_OTP_BLOCK_SIZE 32 + +void flash_otp_init(void); + +secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, + uint8_t datalen); +secbool __wur flash_otp_write(uint8_t block, uint8_t offset, + const uint8_t *data, uint8_t datalen); +secbool __wur flash_otp_lock(uint8_t block); +secbool __wur flash_otp_is_locked(uint8_t block); + +#endif // TREZORHAL_FLASH_OTP_H diff --git a/core/embed/trezorhal/haptic.h b/core/embed/trezorhal/haptic.h new file mode 100644 index 00000000000..2cd4c2911c9 --- /dev/null +++ b/core/embed/trezorhal/haptic.h @@ -0,0 +1,26 @@ + +#ifndef TREZORHAL_HAPTIC_H +#define TREZORHAL_HAPTIC_H + +#include +#include + +typedef enum { + HAPTIC_BUTTON_PRESS = 0, + HAPTIC_ALERT = 1, + HAPTIC_HOLD_TO_CONFIRM = 2, +} haptic_effect_t; + +// Initialize haptic driver +void haptic_init(void); + +// Calibrate haptic driver +void haptic_calibrate(void); + +// Test haptic driver, plays a maximum amplitude for the given duration +bool haptic_test(uint16_t duration_ms); + +// Play haptic effect +void haptic_play(haptic_effect_t effect); + +#endif diff --git a/core/embed/trezorhal/hash_processor.h b/core/embed/trezorhal/hash_processor.h new file mode 100644 index 00000000000..1ebc9bb94da --- /dev/null +++ b/core/embed/trezorhal/hash_processor.h @@ -0,0 +1,33 @@ +#ifndef TREZORHAL_HASH_PROCESSOR_H_ +#define TREZORHAL_HASH_PROCESSOR_H_ + +#include + +#define HASH_SHA256_BUFFER_SIZE 4 + +typedef struct { + uint32_t length; /*!< nb bytes in buffer */ + uint8_t buffer[HASH_SHA256_BUFFER_SIZE]; /*!< data being processed */ +} hash_sha265_context_t; + +// Initialize the hash processor +void hash_processor_init(void); + +// Calculate SHA256 hash of data +// for best performance, data should be 32-bit aligned - as this allows DMA to +// be used +void hash_processor_sha256_calc(const uint8_t *data, uint32_t len, + uint8_t *hash); + +// Initialize the hash context +// This serves for calculating hashes of multiple data blocks +void hash_processor_sha256_init(hash_sha265_context_t *ctx); + +// Feed the hash next chunk of data +void hash_processor_sha256_update(hash_sha265_context_t *ctx, + const uint8_t *data, uint32_t len); + +// Finalize the hash calculation, retrieve the digest +void hash_processor_sha256_final(hash_sha265_context_t *ctx, uint8_t *output); + +#endif diff --git a/core/embed/trezorhal/lowlevel.h b/core/embed/trezorhal/lowlevel.h index 49757aeac94..af207d6aec9 100644 --- a/core/embed/trezorhal/lowlevel.h +++ b/core/embed/trezorhal/lowlevel.h @@ -27,6 +27,7 @@ void flash_lock_option_bytes(void); void flash_unlock_option_bytes(void); uint32_t flash_set_option_bytes(void); secbool flash_configure_option_bytes(void); +secbool flash_configure_sec_area_ob(void); void periph_init(void); secbool reset_flags_check(void); void reset_flags_reset(void); diff --git a/core/embed/trezorhal/mpu.h b/core/embed/trezorhal/mpu.h index 11db675596c..a4aa0372829 100644 --- a/core/embed/trezorhal/mpu.h +++ b/core/embed/trezorhal/mpu.h @@ -21,8 +21,11 @@ #define __MPU_H__ void mpu_config_off(void); +void mpu_config_boardloader(void); void mpu_config_bootloader(void); +void mpu_config_firmware_initial(void); void mpu_config_firmware(void); +void mpu_config_prodtest_initial(void); void mpu_config_prodtest(void); #endif diff --git a/core/embed/trezorhal/secret.h b/core/embed/trezorhal/secret.h index 33668014736..2b226c3d676 100644 --- a/core/embed/trezorhal/secret.h +++ b/core/embed/trezorhal/secret.h @@ -7,6 +7,12 @@ #define SECRET_OPTIGA_KEY_OFFSET 16 #define SECRET_OPTIGA_KEY_LEN 32 +#define SECRET_MONOTONIC_COUNTER_OFFSET 48 +#define SECRET_MONOTONIC_COUNTER_LEN 1024 + +#define SECRET_BHK_OFFSET (1024 * 8) +#define SECRET_BHK_LEN 32 + secbool secret_bootloader_locked(void); void secret_write(uint8_t* data, uint32_t offset, uint32_t len); @@ -17,4 +23,22 @@ secbool secret_wiped(void); void secret_erase(void); +void secret_hide(void); + void secret_write_header(void); + +void secret_optiga_backup(void); + +void secret_optiga_hide(void); + +secbool secret_optiga_extract(uint8_t* dest); + +void secret_bhk_lock(void); + +secbool secret_bhk_locked(void); + +void secret_bhk_regenerate(void); + +void secret_bhk_provision(void); + +secbool secret_optiga_present(void); diff --git a/core/embed/trezorhal/secure_aes.h b/core/embed/trezorhal/secure_aes.h new file mode 100644 index 00000000000..78dedce73bf --- /dev/null +++ b/core/embed/trezorhal/secure_aes.h @@ -0,0 +1,40 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#ifndef TREZOR_HAL_SECURE_AES_H +#define TREZOR_HAL_SECURE_AES_H + +#include +#include +#include + +// Initializes secure AES module +secbool secure_aes_init(void); + +// Encrypts a block of data using AES-256 EBB and (DHUK xor BHK) key +// Input and output must be aligned to 32 bits, size is in bytes +secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output); + +// Decrypts a block of data using AES-256 ECB and (DHUK xor BHK) key +// Input and output must be aligned to 32 bits, size is in bytes +secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output); + +void secure_aes_test(); + +#endif // TREZOR_HAL_SECURE_AES_H diff --git a/core/embed/trezorhal/stm32f4/backlight_pwm.c b/core/embed/trezorhal/stm32f4/backlight_pwm.c index 9cddd1972b6..becf4602fa3 100644 --- a/core/embed/trezorhal/stm32f4/backlight_pwm.c +++ b/core/embed/trezorhal/stm32f4/backlight_pwm.c @@ -29,7 +29,7 @@ void backlight_pwm_init(void) { GPIO_InitTypeDef GPIO_InitStructure; - // LCD_PWM/PA7 (backlight control) + // LCD_PWM (backlight control) GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; @@ -37,34 +37,113 @@ void backlight_pwm_init(void) { GPIO_InitStructure.Pin = BACKLIGHT_PWM_PIN; HAL_GPIO_Init(BACKLIGHT_PWM_PORT, &GPIO_InitStructure); - // enable PWM timer - TIM_HandleTypeDef TIM_Handle; - TIM_Handle.Instance = BACKLIGHT_PWM_TIM; - TIM_Handle.Init.Period = LED_PWM_TIM_PERIOD - 1; - // TIM1/APB2 source frequency equals to SystemCoreClock in our configuration, - // we want 1 MHz - TIM_Handle.Init.Prescaler = LED_PWM_PRESCALER; - TIM_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; - TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; - TIM_Handle.Init.RepetitionCounter = 0; - HAL_TIM_PWM_Init(&TIM_Handle); + uint32_t tmpcr1 = 0; + + /* Select the Counter Mode */ + tmpcr1 |= TIM_COUNTERMODE_UP; + + /* Set the clock division */ + tmpcr1 |= (uint32_t)TIM_CLOCKDIVISION_DIV1; + + /* Set the auto-reload preload */ +#ifdef STM32U5 + tmpcr1 |= TIM_AUTORELOAD_PRELOAD_DISABLE; +#endif + + BACKLIGHT_PWM_TIM->CR1 = tmpcr1; + + /* Set the Autoreload value */ + BACKLIGHT_PWM_TIM->ARR = (uint32_t)LED_PWM_TIM_PERIOD - 1; + + /* Set the Prescaler value */ + BACKLIGHT_PWM_TIM->PSC = LED_PWM_PRESCALER; + + /* Set the Repetition Counter value */ + BACKLIGHT_PWM_TIM->RCR = 0; + + /* Generate an update event to reload the Prescaler + and the repetition counter (only for advanced timer) value immediately */ + BACKLIGHT_PWM_TIM->EGR = TIM_EGR_UG; + pwm_period = LED_PWM_TIM_PERIOD; - TIM_OC_InitTypeDef TIM_OC_InitStructure; - TIM_OC_InitStructure.Pulse = 0; - TIM_OC_InitStructure.OCMode = BACKLIGHT_PWM_TIM_OCMODE; - TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_HIGH; - TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE; - TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH; - TIM_OC_InitStructure.OCIdleState = TIM_OCIDLESTATE_SET; - TIM_OC_InitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET; - HAL_TIM_PWM_ConfigChannel(&TIM_Handle, &TIM_OC_InitStructure, - BACKLIGHT_PWM_TIM_CHANNEL); + /* Set the Preload enable bit for channel1 */ + BACKLIGHT_PWM_TIM->CCMR1 |= TIM_CCMR1_OC1PE; + + /* Configure the Output Fast mode */ + BACKLIGHT_PWM_TIM->CCMR1 &= ~TIM_CCMR1_OC1FE; + BACKLIGHT_PWM_TIM->CCMR1 |= TIM_OCFAST_DISABLE; + + uint32_t tmpccmrx; + uint32_t tmpccer; + uint32_t tmpcr2; + + /* Get the TIMx CCER register value */ + tmpccer = BACKLIGHT_PWM_TIM->CCER; + + /* Disable the Channel 1: Reset the CC1E Bit */ + BACKLIGHT_PWM_TIM->CCER &= ~TIM_CCER_CC1E; + tmpccer |= TIM_CCER_CC1E; + + /* Get the TIMx CR2 register value */ + tmpcr2 = BACKLIGHT_PWM_TIM->CR2; + + /* Get the TIMx CCMR1 register value */ + tmpccmrx = BACKLIGHT_PWM_TIM->CCMR1; + + /* Reset the Output Compare Mode Bits */ + tmpccmrx &= ~TIM_CCMR1_OC1M; + tmpccmrx &= ~TIM_CCMR1_CC1S; + /* Select the Output Compare Mode */ + tmpccmrx |= BACKLIGHT_PWM_TIM_OCMODE; + + /* Reset the Output Polarity level */ + tmpccer &= ~TIM_CCER_CC1P; + /* Set the Output Compare Polarity */ + tmpccer |= TIM_OCPOLARITY_HIGH; + + if (IS_TIM_CCXN_INSTANCE(BACKLIGHT_PWM_TIM, TIM_CHANNEL_1)) { + /* Check parameters */ + assert_param(IS_TIM_OCN_POLARITY(OC_Config->OCNPolarity)); + + /* Reset the Output N Polarity level */ + tmpccer &= ~TIM_CCER_CC1NP; + /* Set the Output N Polarity */ + tmpccer |= TIM_OCNPOLARITY_HIGH; + /* Set the Output N State */ + tmpccer |= TIM_CCER_CC1NE; + } + + if (IS_TIM_BREAK_INSTANCE(BACKLIGHT_PWM_TIM)) { + /* Check parameters */ + assert_param(IS_TIM_OCNIDLE_STATE(OC_Config->OCNIdleState)); + assert_param(IS_TIM_OCIDLE_STATE(OC_Config->OCIdleState)); + + /* Reset the Output Compare and Output Compare N IDLE State */ + tmpcr2 &= ~TIM_CR2_OIS1; + tmpcr2 &= ~TIM_CR2_OIS1N; + /* Set the Output Idle state */ + tmpcr2 |= TIM_OCIDLESTATE_SET; + /* Set the Output N Idle state */ + tmpcr2 |= TIM_OCNIDLESTATE_SET; + } + + /* Write to TIMx CR2 */ + BACKLIGHT_PWM_TIM->CR2 = tmpcr2; + + /* Write to TIMx CCMR1 */ + BACKLIGHT_PWM_TIM->CCMR1 = tmpccmrx; + + /* Set the Capture Compare Register value */ + BACKLIGHT_PWM_TIM->CCR1 = 0; + + /* Write to TIMx CCER */ + BACKLIGHT_PWM_TIM->CCER = tmpccer; backlight_pwm_set(0); - HAL_TIM_PWM_Start(&TIM_Handle, BACKLIGHT_PWM_TIM_CHANNEL); - HAL_TIMEx_PWMN_Start(&TIM_Handle, BACKLIGHT_PWM_TIM_CHANNEL); + BACKLIGHT_PWM_TIM->BDTR |= TIM_BDTR_MOE; + BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_CEN; } void backlight_pwm_reinit(void) { diff --git a/core/embed/trezorhal/stm32f4/board_capabilities.c b/core/embed/trezorhal/stm32f4/board_capabilities.c index abfd95d7169..053987043f9 100644 --- a/core/embed/trezorhal/stm32f4/board_capabilities.c +++ b/core/embed/trezorhal/stm32f4/board_capabilities.c @@ -20,6 +20,7 @@ #include "board_capabilities.h" #include #include "common.h" +#include "model.h" #define handle_fault(msg) \ (__fatal_error("Fault detected", msg, __FILE__, __LINE__, __func__)) diff --git a/core/embed/trezorhal/stm32f4/boot_args.c b/core/embed/trezorhal/stm32f4/boot_args.c new file mode 100644 index 00000000000..70caf21fc6d --- /dev/null +++ b/core/embed/trezorhal/stm32f4/boot_args.c @@ -0,0 +1,44 @@ + +#include "../boot_args.h" +#include +#include + +// The 'g_boot_command_shadow' shadows a real boot command passed +// to the bootloader. +// 1. In the bootloader, its value is set in the startup code. +// 2. In the firmware it holds command for the next boot and it is used +// when svc_reboot_to_bootloader() is called +boot_command_t g_boot_command_shadow; + +#ifdef STM32U5 +// The 'g_boot_command' is persistent variable that holds the 'command' +// for the next reboot/jump to the bootloader. Its value is set to +// g_boot_command_shadow when 'svc_reboot_to_bootloader()' is called. +boot_command_t __attribute__((section(".boot_command"))) g_boot_command; +#endif + +// The 'g_boot_args' is persistent array that stores extra arguments passed +// to the function bootargs_set. +static boot_args_t __attribute__((section(".boot_args"))) g_boot_args; + +void bootargs_set(boot_command_t command, const void* args, size_t args_size) { + // save boot command + g_boot_command_shadow = command; + + size_t copy_size = 0; + // copy arguments up to BOOT_ARGS_MAX_SIZE + if (args != NULL && args_size > 0) { + copy_size = MIN(args_size, BOOT_ARGS_MAX_SIZE); + memcpy(&g_boot_args.raw[0], args, copy_size); + } + + // clear rest of boot_args array + size_t clear_size = BOOT_ARGS_MAX_SIZE - copy_size; + if (clear_size > 0) { + memset(&g_boot_args.raw[copy_size], 0, clear_size); + } +} + +boot_command_t bootargs_get_command() { return g_boot_command_shadow; } + +const boot_args_t* bootargs_get_args() { return &g_boot_args; } diff --git a/core/embed/trezorhal/stm32f4/common.c b/core/embed/trezorhal/stm32f4/common.c index 79ff1645ca2..5e8eb5472fb 100644 --- a/core/embed/trezorhal/stm32f4/common.c +++ b/core/embed/trezorhal/stm32f4/common.c @@ -29,7 +29,7 @@ #ifdef FANCY_FATAL_ERROR #include "rust_ui.h" #endif -#include "flash.h" +#include "flash_otp.h" #include "platform.h" #include "rand.h" #include "supervise.h" diff --git a/core/embed/trezorhal/stm32f4/displays/st7789v.c b/core/embed/trezorhal/stm32f4/displays/st7789v.c index 801a0812740..53c0d2ac9f8 100644 --- a/core/embed/trezorhal/stm32f4/displays/st7789v.c +++ b/core/embed/trezorhal/stm32f4/displays/st7789v.c @@ -39,8 +39,11 @@ // differencies in the resulting binaries. const volatile uint8_t DISPLAY_ST7789V_INVERT_COLORS = 1; -// FSMC/FMC Bank 1 - NOR/PSRAM 1 -#define DISPLAY_MEMORY_BASE 0x60000000 +#ifndef FMC_BANK1 +#define FMC_BANK1 0x60000000U +#endif + +#define DISPLAY_MEMORY_BASE FMC_BANK1 #define DISPLAY_MEMORY_PIN 16 #ifdef USE_DISP_I8080_16BIT_DW #define DISPLAY_ADDR_SHIFT 2 @@ -197,7 +200,7 @@ int display_orientation(int degrees) { lx154a2422_rotate(degrees, &DISPLAY_PADDING); } #else - DISPLAY_PANEL_ROTATE(degrees, &BUFFER_OFFSET); + DISPLAY_PANEL_ROTATE(degrees, &DISPLAY_PADDING); #endif } } @@ -260,7 +263,6 @@ void display_setup_fmc(void) { FMC_BURST_ACCESS_MODE_DISABLE; external_display_data_sram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; - external_display_data_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE; external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; diff --git a/core/embed/trezorhal/stm32f4/fault_handlers.c b/core/embed/trezorhal/stm32f4/fault_handlers.c new file mode 100644 index 00000000000..ea8b8b471ab --- /dev/null +++ b/core/embed/trezorhal/stm32f4/fault_handlers.c @@ -0,0 +1,23 @@ +#include "common.h" + +void fault_handlers_init(void) { + // Enable BUS fault and USAGE fault handlers + SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); +} + +void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } + +void MemManage_Handler_MM(void) { error_shutdown("INTERNAL ERROR", "(MM)"); } + +void MemManage_Handler_SO(void) { error_shutdown("INTERNAL ERROR", "(SO)"); } + +void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(BF)"); } + +void UsageFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(UF)"); } + +void NMI_Handler(void) { + // Clock Security System triggered NMI + if ((RCC->CIR & RCC_CIR_CSSF) != 0) { + error_shutdown("INTERNAL ERROR", "(CS)"); + } +} diff --git a/core/embed/trezorhal/stm32f4/flash.c b/core/embed/trezorhal/stm32f4/flash.c index ba57c08c013..8a34cc6947f 100644 --- a/core/embed/trezorhal/stm32f4/flash.c +++ b/core/embed/trezorhal/stm32f4/flash.c @@ -78,26 +78,6 @@ static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { #endif }; -uint32_t flash_wait_and_clear_status_flags(void) { - while (FLASH->SR & FLASH_SR_BSY) - ; // wait for all previous flash operations to complete - const uint32_t result = - FLASH->SR & FLASH_STATUS_ALL_FLAGS; // get the current status flags - FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags - return result; -} - -secbool flash_unlock_write(void) { - HAL_FLASH_Unlock(); - FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags - return sectrue; -} - -secbool flash_lock_write(void) { - HAL_FLASH_Lock(); - return sectrue; -} - const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) { if (sector >= FLASH_SECTOR_COUNT) { return NULL; @@ -110,105 +90,71 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) { return (const void *)addr; } -uint32_t flash_sector_size(uint16_t sector) { - if (sector >= FLASH_SECTOR_COUNT) { +uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) { + if (first_sector + sector_count > FLASH_SECTOR_COUNT) { return 0; } - return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + return FLASH_SECTOR_TABLE[first_sector + sector_count] - + FLASH_SECTOR_TABLE[first_sector]; } -secbool flash_area_erase_bulk(const flash_area_t *area, int count, - void (*progress)(int pos, int len)) { - ensure(flash_unlock_write(), NULL); - FLASH_EraseInitTypeDef EraseInitStruct = {0}; - EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; - EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; - EraseInitStruct.NbSectors = 1; +uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) { + uint16_t sector = first_sector; - int total_sectors = 0; - int done_sectors = 0; - for (int a = 0; a < count; a++) { - for (int i = 0; i < area[a].num_subareas; i++) { - total_sectors += area[a].subarea[i].num_sectors; + while (sector < FLASH_SECTOR_COUNT) { + uint32_t sector_size = + FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + + if (offset < sector_size) { + break; } - } - if (progress) { - progress(0, total_sectors); + offset -= sector_size; + sector++; } - for (int a = 0; a < count; a++) { - for (int s = 0; s < area[a].num_subareas; s++) { - for (int i = 0; i < area[a].subarea[s].num_sectors; i++) { - int sector = area[a].subarea[s].first_sector + i; + return sector; +} - EraseInitStruct.Sector = sector; - uint32_t SectorError; - if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { - ensure(flash_lock_write(), NULL); - return secfalse; - } - // check whether the sector was really deleted (contains only 0xFF) - const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], - addr_end = FLASH_SECTOR_TABLE[sector + 1]; - for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { - if (*((const uint32_t *)addr) != 0xFFFFFFFF) { - ensure(flash_lock_write(), NULL); - return secfalse; - } - } - done_sectors++; - if (progress) { - progress(done_sectors, total_sectors); - } - } - } - } - ensure(flash_lock_write(), NULL); +secbool flash_unlock_write(void) { + HAL_FLASH_Unlock(); + FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags return sectrue; } -secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset, - uint32_t *bytes_erased) { - uint32_t sector_offset = 0; - *bytes_erased = 0; - - for (int s = 0; s < area->num_subareas; s++) { - for (int i = 0; i < area->subarea[s].num_sectors; i++) { - uint32_t sector_index = area->subarea[s].first_sector + i; - uint32_t sector_size = FLASH_SECTOR_TABLE[sector_index + 1] - - FLASH_SECTOR_TABLE[sector_index]; - - if (offset == sector_offset) { - ensure(flash_unlock_write(), NULL); +secbool flash_lock_write(void) { + HAL_FLASH_Lock(); + return sectrue; +} - FLASH_EraseInitTypeDef erase_init = { - .TypeErase = FLASH_TYPEERASE_SECTORS, - .VoltageRange = FLASH_VOLTAGE_RANGE_3, - .Sector = sector_index, - .NbSectors = 1}; +secbool flash_sector_erase(uint16_t sector) { + if (sector >= FLASH_SECTOR_COUNT) { + return secfalse; + } - uint32_t sector_error; + FLASH_EraseInitTypeDef EraseInitStruct = { + .TypeErase = FLASH_TYPEERASE_SECTORS, + .VoltageRange = FLASH_VOLTAGE_RANGE_3, + .Sector = sector, + .NbSectors = 1, + }; - if (HAL_FLASHEx_Erase(&erase_init, §or_error) != HAL_OK) { - ensure(flash_lock_write(), NULL); - return secfalse; - } + uint32_t sector_error; - ensure(flash_lock_write(), NULL); + if (HAL_FLASHEx_Erase(&EraseInitStruct, §or_error) != HAL_OK) { + return secfalse; + } - *bytes_erased = sector_size; - return sectrue; - } + // check whether the sector was really deleted (contains only 0xFF) + uint32_t addr_start = FLASH_SECTOR_TABLE[sector]; + uint32_t addr_end = FLASH_SECTOR_TABLE[sector + 1]; - sector_offset += sector_size; + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + return secfalse; } } - if (offset == sector_offset) { - return sectrue; - } - - return secfalse; + return sectrue; } secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) { @@ -252,51 +198,3 @@ secbool flash_write_block(uint16_t sector, uint32_t offset, const flash_block_t block) { return flash_write_word(sector, offset, block[0]); } - -#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U - -secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, - uint8_t datalen) { - if (block >= FLASH_OTP_NUM_BLOCKS || - offset + datalen > FLASH_OTP_BLOCK_SIZE) { - return secfalse; - } - for (uint8_t i = 0; i < datalen; i++) { - data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + - offset + i); - } - return sectrue; -} - -secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, - uint8_t datalen) { - if (block >= FLASH_OTP_NUM_BLOCKS || - offset + datalen > FLASH_OTP_BLOCK_SIZE) { - return secfalse; - } - ensure(flash_unlock_write(), NULL); - for (uint8_t i = 0; i < datalen; i++) { - uint32_t address = - FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; - ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, - address, data[i])), - NULL); - } - ensure(flash_lock_write(), NULL); - return sectrue; -} - -secbool flash_otp_lock(uint8_t block) { - if (block >= FLASH_OTP_NUM_BLOCKS) { - return secfalse; - } - ensure(flash_unlock_write(), NULL); - HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, - FLASH_OTP_LOCK_BASE + block, 0x00); - ensure(flash_lock_write(), NULL); - return sectrue * (ret == HAL_OK); -} - -secbool flash_otp_is_locked(uint8_t block) { - return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block)); -} diff --git a/core/embed/trezorhal/stm32f4/flash_otp.c b/core/embed/trezorhal/stm32f4/flash_otp.c new file mode 100644 index 00000000000..28fbb34ffbf --- /dev/null +++ b/core/embed/trezorhal/stm32f4/flash_otp.c @@ -0,0 +1,76 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include STM32_HAL_H + +#include "flash_otp.h" +#include "common.h" +#include "flash.h" + +#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U + +void flash_otp_init() { + // intentionally left empty +} + +secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, + uint8_t datalen) { + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return secfalse; + } + for (uint8_t i = 0; i < datalen; i++) { + data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + + offset + i); + } + return sectrue; +} + +secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, + uint8_t datalen) { + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return secfalse; + } + ensure(flash_unlock_write(), NULL); + for (uint8_t i = 0; i < datalen; i++) { + uint32_t address = + FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; + ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, + address, data[i])), + NULL); + } + ensure(flash_lock_write(), NULL); + return sectrue; +} + +secbool flash_otp_lock(uint8_t block) { + if (block >= FLASH_OTP_NUM_BLOCKS) { + return secfalse; + } + ensure(flash_unlock_write(), NULL); + HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, + FLASH_OTP_LOCK_BASE + block, 0x00); + ensure(flash_lock_write(), NULL); + return sectrue * (ret == HAL_OK); +} + +secbool flash_otp_is_locked(uint8_t block) { + return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block)); +} diff --git a/core/embed/trezorhal/stm32f4/i2c.c b/core/embed/trezorhal/stm32f4/i2c.c index ba65738c69a..16cfd156cc5 100644 --- a/core/embed/trezorhal/stm32f4/i2c.c +++ b/core/embed/trezorhal/stm32f4/i2c.c @@ -18,6 +18,16 @@ typedef struct { } i2c_instance_t; i2c_instance_t i2c_defs[I2C_COUNT] = { + { + .Instance = I2C_INSTANCE_0, + .SclPort = I2C_INSTANCE_0_SCL_PORT, + .SdaPort = I2C_INSTANCE_0_SDA_PORT, + .SclPin = I2C_INSTANCE_0_SCL_PIN, + .SdaPin = I2C_INSTANCE_0_SDA_PIN, + .PinAF = I2C_INSTANCE_0_PIN_AF, + .Reset = I2C_INSTANCE_0_RESET_FLG, + }, +#ifdef I2C_INSTANCE_1 { .Instance = I2C_INSTANCE_1, .SclPort = I2C_INSTANCE_1_SCL_PORT, @@ -27,16 +37,6 @@ i2c_instance_t i2c_defs[I2C_COUNT] = { .PinAF = I2C_INSTANCE_1_PIN_AF, .Reset = I2C_INSTANCE_1_RESET_FLG, }, -#ifdef I2C_INSTANCE_2 - { - .Instance = I2C_INSTANCE_2, - .SclPort = I2C_INSTANCE_2_SCL_PORT, - .SdaPort = I2C_INSTANCE_2_SDA_PORT, - .SclPin = I2C_INSTANCE_2_SCL_PIN, - .SdaPin = I2C_INSTANCE_2_SDA_PIN, - .PinAF = I2C_INSTANCE_2_PIN_AF, - .Reset = I2C_INSTANCE_2_RESET_FLG, - }, #endif }; @@ -60,7 +60,6 @@ void i2c_init_instance(uint16_t idx, i2c_instance_t *instance) { HAL_GPIO_Init(instance->SclPort, &GPIO_InitStructure); GPIO_InitStructure.Alternate = instance->PinAF; - ; GPIO_InitStructure.Pin = instance->SdaPin; HAL_GPIO_Init(instance->SdaPort, &GPIO_InitStructure); @@ -82,16 +81,16 @@ void i2c_init_instance(uint16_t idx, i2c_instance_t *instance) { void i2c_init(void) { // enable I2C clock - I2C_INSTANCE_1_CLK_EN(); - I2C_INSTANCE_1_SCL_CLK_EN(); - I2C_INSTANCE_1_SDA_CLK_EN(); + I2C_INSTANCE_0_CLK_EN(); + I2C_INSTANCE_0_SCL_CLK_EN(); + I2C_INSTANCE_0_SDA_CLK_EN(); i2c_init_instance(0, &i2c_defs[0]); -#ifdef I2C_INSTANCE_2 - I2C_INSTANCE_2_CLK_EN(); - I2C_INSTANCE_2_SCL_CLK_EN(); - I2C_INSTANCE_2_SDA_CLK_EN(); +#ifdef I2C_INSTANCE_1 + I2C_INSTANCE_1_CLK_EN(); + I2C_INSTANCE_1_SCL_CLK_EN(); + I2C_INSTANCE_1_SDA_CLK_EN(); i2c_init_instance(1, &i2c_defs[1]); #endif } diff --git a/core/embed/trezorhal/stm32f4/irq.h b/core/embed/trezorhal/stm32f4/irq.h index 1d06d4f958c..319755f1c5a 100644 --- a/core/embed/trezorhal/stm32f4/irq.h +++ b/core/embed/trezorhal/stm32f4/irq.h @@ -160,4 +160,7 @@ static inline void restore_irq_pri(uint32_t state) { #define IRQ_PRI_PENDSV NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) #define IRQ_PRI_RTC_WKUP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) +// !@# TAMPER interrupt priority should be probably much higher +#define IRQ_PRI_TAMP NVIC_EncodePriority(NVIC_PRIORITYGROUP_4, 15, 0) + #endif // MICROPY_INCLUDED_STM32_IRQ_H diff --git a/core/embed/trezorhal/stm32f4/lowlevel.c b/core/embed/trezorhal/stm32f4/lowlevel.c index 6170e69fbaf..31879238a0b 100644 --- a/core/embed/trezorhal/stm32f4/lowlevel.c +++ b/core/embed/trezorhal/stm32f4/lowlevel.c @@ -20,7 +20,7 @@ #include STM32_HAL_H #include "lowlevel.h" -#include "flash.h" +#include "flash_otp.h" #pragma GCC optimize( \ "no-stack-protector") // applies to all functions in this file @@ -57,6 +57,19 @@ #define OPTION_BYTES_BANK1_WRP (*(volatile uint16_t* const)0x1FFFC008U) #define OPTION_BYTES_BANK2_WRP (*(volatile uint16_t* const)0x1FFEC008U) +#define FLASH_STATUS_ALL_FLAGS \ + (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | \ + FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) + +static uint32_t flash_wait_and_clear_status_flags(void) { + while (FLASH->SR & FLASH_SR_BSY) + ; // wait for all previous flash operations to complete + const uint32_t result = + FLASH->SR & FLASH_STATUS_ALL_FLAGS; // get the current status flags + FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags + return result; +} + secbool flash_check_option_bytes(void) { flash_wait_and_clear_status_flags(); // check values stored in flash interface registers diff --git a/core/embed/trezorhal/stm32f4/mpu.c b/core/embed/trezorhal/stm32f4/mpu.c index 98de82371e4..af40d3814db 100644 --- a/core/embed/trezorhal/stm32f4/mpu.c +++ b/core/embed/trezorhal/stm32f4/mpu.c @@ -33,6 +33,10 @@ void mpu_config_off(void) { HAL_MPU_Disable(); } +void mpu_config_boardloader(void) { + // nothing to be done +} + void mpu_config_bootloader(void) { // Disable MPU HAL_MPU_Disable(); @@ -100,6 +104,8 @@ void mpu_config_bootloader(void) { HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); } +void mpu_config_firmware_initial(void) {} + void mpu_config_firmware(void) { // Disable MPU HAL_MPU_Disable(); @@ -206,6 +212,8 @@ void mpu_config_firmware(void) { __asm__ volatile("isb"); } +void mpu_config_prodtest_initial(void) {} + void mpu_config_prodtest(void) { // Disable MPU HAL_MPU_Disable(); diff --git a/core/embed/trezorhal/stm32f4/optiga_hal.c b/core/embed/trezorhal/stm32f4/optiga_hal.c index 0a3f92acb22..8f9fd773429 100644 --- a/core/embed/trezorhal/stm32f4/optiga_hal.c +++ b/core/embed/trezorhal/stm32f4/optiga_hal.c @@ -3,26 +3,27 @@ #include TREZOR_BOARD void optiga_hal_init(void) { + OPTIGA_RST_CLK_EN(); // init reset pin GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStructure.Pull = GPIO_NOPULL; GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStructure.Alternate = 0; - GPIO_InitStructure.Pin = GPIO_PIN_9; - HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + GPIO_InitStructure.Pin = OPTIGA_RST_PIN; + HAL_GPIO_Init(OPTIGA_RST_PORT, &GPIO_InitStructure); // perform reset on every initialization - HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, GPIO_PIN_RESET); + HAL_GPIO_WritePin(OPTIGA_RST_PORT, OPTIGA_RST_PIN, GPIO_PIN_RESET); hal_delay(10); - HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, GPIO_PIN_SET); + HAL_GPIO_WritePin(OPTIGA_RST_PORT, OPTIGA_RST_PIN, GPIO_PIN_SET); // warm reset startup time min 15ms hal_delay(20); } void optiga_reset(void) { - HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, GPIO_PIN_RESET); + HAL_GPIO_WritePin(OPTIGA_RST_PORT, OPTIGA_RST_PIN, GPIO_PIN_RESET); hal_delay(10); - HAL_GPIO_WritePin(GPIOD, GPIO_PIN_9, GPIO_PIN_SET); + HAL_GPIO_WritePin(OPTIGA_RST_PORT, OPTIGA_RST_PIN, GPIO_PIN_SET); // warm reset startup time min 15ms hal_delay(20); } diff --git a/core/embed/trezorhal/stm32f4/platform.h b/core/embed/trezorhal/stm32f4/platform.h index 89b7c2acc7d..0c02ee1c8a7 100644 --- a/core/embed/trezorhal/stm32f4/platform.h +++ b/core/embed/trezorhal/stm32f4/platform.h @@ -23,6 +23,8 @@ #include STM32_HAL_H #include +#define SENSITIVE + typedef enum { CLOCK_180_MHZ = 0, CLOCK_168_MHZ = 1, diff --git a/core/embed/trezorhal/stm32f4/secret.c b/core/embed/trezorhal/stm32f4/secret.c index 2232f889a76..33e8b66e5b5 100644 --- a/core/embed/trezorhal/stm32f4/secret.c +++ b/core/embed/trezorhal/stm32f4/secret.c @@ -72,3 +72,7 @@ secbool secret_wiped(void) { void secret_erase(void) { ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); } + +secbool secret_optiga_extract(uint8_t* dest) { + return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); +} diff --git a/core/embed/trezorhal/stm32f4/supervise.c b/core/embed/trezorhal/stm32f4/supervise.c index 0a52028e6dd..c1ea8f75aa0 100644 --- a/core/embed/trezorhal/stm32f4/supervise.c +++ b/core/embed/trezorhal/stm32f4/supervise.c @@ -8,26 +8,16 @@ #ifdef ARM_USER_MODE -// Saves extra parameters for the bootloader -static void _copy_boot_args(const void *args, size_t args_size) { - // symbols imported from the linker script - extern uint8_t boot_args_start; - extern uint8_t boot_args_end; - - uint8_t *p = &boot_args_start; - - if (args != NULL && args_size > 0) { - size_t max_size = &boot_args_end - &boot_args_start; - size_t copy_size = MIN(args_size, max_size); - memcpy(p, args, copy_size); - p += args_size; - } - - if (p < &boot_args_end) { - memset(p, 0, &boot_args_end - p); - } +#ifdef STM32U5 +extern uint32_t g_boot_command; +__attribute__((noreturn)) static void _reboot_to_bootloader( + boot_command_t boot_command) { + g_boot_command = boot_command; + __disable_irq(); + delete_secrets(); + NVIC_SystemReset(); } - +#else __attribute__((noreturn)) static void _reboot_to_bootloader( boot_command_t boot_command) { mpu_config_bootloader(); @@ -35,10 +25,10 @@ __attribute__((noreturn)) static void _reboot_to_bootloader( for (;;) ; } +#endif -void svc_reboot_to_bootloader(boot_command_t boot_command, const void *args, - size_t args_size) { - _copy_boot_args(args, args_size); +void svc_reboot_to_bootloader(void) { + boot_command_t boot_command = bootargs_get_command(); if (is_mode_unprivileged() && !is_mode_handler()) { register uint32_t r0 __asm__("r0") = boot_command; __asm__ __volatile__("svc %0" ::"i"(SVC_REBOOT_TO_BOOTLOADER), "r"(r0) diff --git a/core/embed/trezorhal/stm32f4/supervise.h b/core/embed/trezorhal/stm32f4/supervise.h index 95965ccf08e..c4a70650ed0 100644 --- a/core/embed/trezorhal/stm32f4/supervise.h +++ b/core/embed/trezorhal/stm32f4/supervise.h @@ -68,8 +68,7 @@ static inline void svc_shutdown(void) { } } -void svc_reboot_to_bootloader(boot_command_t boot_command, const void* args, - size_t args_size); +void svc_reboot_to_bootloader(void); static inline uint32_t svc_get_systick_val(void) { if (is_mode_unprivileged() && !is_mode_handler()) { diff --git a/core/embed/trezorhal/stm32f4/touch/ft6x36.c b/core/embed/trezorhal/stm32f4/touch/ft6x36.c index 38d338168ec..b7c59bbebc9 100644 --- a/core/embed/trezorhal/stm32f4/touch/ft6x36.c +++ b/core/embed/trezorhal/stm32f4/touch/ft6x36.c @@ -45,7 +45,11 @@ #define EVENT_OLD_TIMEOUT_MS 50 #define EVENT_MISSING_TIMEOUT_MS 50 +static uint32_t touch_init_ticks = 0; + static void touch_default_pin_state(void) { + GPIO_PinState state = HAL_GPIO_ReadPin(TOUCH_ON_PORT, TOUCH_ON_PIN); + // set power off and other pins as per section 3.5 of FT6236 datasheet HAL_GPIO_WritePin(TOUCH_ON_PORT, TOUCH_ON_PIN, GPIO_PIN_SET); // CTP_ON (active low) i.e.- CTPM power @@ -74,7 +78,11 @@ static void touch_default_pin_state(void) { // for these changes to take effect. a reset needs to be low for // a minimum of 5ms. also wait for power circuitry to stabilize (if it // changed). - HAL_Delay(100); // 100ms (being conservative) + HAL_Delay(10); + + if (state == GPIO_PIN_SET) { + HAL_Delay(90); // add 90 ms for circuitry to stabilize (being conservative) + } } static void touch_active_pin_state(void) { @@ -93,8 +101,10 @@ static void touch_active_pin_state(void) { HAL_GPIO_WritePin(TOUCH_RST_PORT, TOUCH_RST_PIN, GPIO_PIN_SET); // release CTPM reset - HAL_Delay(310); // "Time of starting to report point after resetting" min is - // 300ms, giving an extra 10ms + + touch_init_ticks = hal_ticks_ms(); + + HAL_Delay(5); } void touch_set_mode(void) { @@ -102,11 +112,12 @@ void touch_set_mode(void) { // generates a pulse when new data is available uint8_t touch_panel_config[] = {0xA4, 0x01}; for (int i = 0; i < 3; i++) { - if (HAL_OK == i2c_transmit(TOUCH_I2C_NUM, TOUCH_ADDRESS, touch_panel_config, - sizeof(touch_panel_config), 10)) { + if (HAL_OK == i2c_transmit(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, + touch_panel_config, sizeof(touch_panel_config), + 10)) { return; } - i2c_cycle(TOUCH_I2C_NUM); + i2c_cycle(TOUCH_I2C_INSTANCE); } ensure(secfalse, "Touch screen panel was not loaded properly."); @@ -117,8 +128,6 @@ void touch_power_on(void) { // turn on CTP circuitry touch_active_pin_state(); - - HAL_Delay(50); } void touch_power_off(void) { @@ -142,16 +151,23 @@ void touch_init(void) { touch_sensitivity(TOUCH_SENSITIVITY); } +void touch_wait_until_ready(void) { + // wait for the touch controller to be ready + while (hal_ticks_ms() - touch_init_ticks < 310) { + HAL_Delay(1); + } +} + void touch_sensitivity(uint8_t value) { // set panel threshold (TH_GROUP) - default value is 0x12 uint8_t touch_panel_threshold[] = {0x80, value}; for (int i = 0; i < 3; i++) { - if (HAL_OK == i2c_transmit(TOUCH_I2C_NUM, TOUCH_ADDRESS, + if (HAL_OK == i2c_transmit(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, touch_panel_threshold, sizeof(touch_panel_threshold), 10)) { return; } - i2c_cycle(TOUCH_I2C_NUM); + i2c_cycle(TOUCH_I2C_INSTANCE); } ensure(secfalse, "Touch screen panel was not loaded properly."); @@ -217,14 +233,14 @@ uint32_t touch_read(void) { last_check_time = hal_ticks_ms(); uint8_t outgoing[] = {0x00}; // start reading from address 0x00 - int result = - i2c_transmit(TOUCH_I2C_NUM, TOUCH_ADDRESS, outgoing, sizeof(outgoing), 1); + int result = i2c_transmit(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, outgoing, + sizeof(outgoing), 1); if (result != HAL_OK) { - if (result == HAL_BUSY) i2c_cycle(TOUCH_I2C_NUM); + if (result == HAL_BUSY) i2c_cycle(TOUCH_I2C_INSTANCE); return 0; } - if (HAL_OK != i2c_receive(TOUCH_I2C_NUM, TOUCH_ADDRESS, touch_data, + if (HAL_OK != i2c_receive(TOUCH_I2C_INSTANCE, TOUCH_ADDRESS, touch_data, TOUCH_PACKET_SIZE, 1)) { return 0; // read failure } diff --git a/core/embed/trezorhal/stm32f4/touch/stmpe811.c b/core/embed/trezorhal/stm32f4/touch/stmpe811.c index 677692ff389..4e21a6aa4fb 100644 --- a/core/embed/trezorhal/stm32f4/touch/stmpe811.c +++ b/core/embed/trezorhal/stm32f4/touch/stmpe811.c @@ -183,7 +183,7 @@ uint32_t I2cxTimeout = /** * @brief I2Cx error treatment function */ -static void I2Cx_Error(void) { i2c_cycle(TOUCH_I2C_NUM); } +static void I2Cx_Error(void) { i2c_cycle(TOUCH_I2C_INSTANCE); } /** * @brief Writes a value in a register of the device through BUS. @@ -194,7 +194,7 @@ static void I2Cx_Error(void) { i2c_cycle(TOUCH_I2C_NUM); } static void I2Cx_WriteData(uint8_t Addr, uint8_t Reg, uint8_t Value) { HAL_StatusTypeDef status = HAL_OK; - status = i2c_mem_write(TOUCH_I2C_NUM, Addr, (uint16_t)Reg, + status = i2c_mem_write(TOUCH_I2C_INSTANCE, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, &Value, 1, I2cxTimeout); /* Check the communication status */ @@ -215,7 +215,7 @@ static void I2Cx_WriteBuffer(uint8_t Addr, uint8_t Reg, uint8_t *pBuffer, uint16_t Length) { HAL_StatusTypeDef status = HAL_OK; - status = i2c_mem_write(TOUCH_I2C_NUM, Addr, (uint16_t)Reg, + status = i2c_mem_write(TOUCH_I2C_INSTANCE, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, pBuffer, Length, I2cxTimeout); /* Check the communication status */ @@ -235,8 +235,8 @@ static uint8_t I2Cx_ReadData(uint8_t Addr, uint8_t Reg) { HAL_StatusTypeDef status = HAL_OK; uint8_t value = 0; - status = i2c_mem_read(TOUCH_I2C_NUM, Addr, Reg, I2C_MEMADD_SIZE_8BIT, &value, - 1, I2cxTimeout); + status = i2c_mem_read(TOUCH_I2C_INSTANCE, Addr, Reg, I2C_MEMADD_SIZE_8BIT, + &value, 1, I2cxTimeout); /* Check the communication status */ if (status != HAL_OK) { @@ -258,7 +258,7 @@ static uint8_t I2Cx_ReadBuffer(uint8_t Addr, uint8_t Reg, uint8_t *pBuffer, uint16_t Length) { HAL_StatusTypeDef status = HAL_OK; - status = i2c_mem_read(TOUCH_I2C_NUM, Addr, (uint16_t)Reg, + status = i2c_mem_read(TOUCH_I2C_INSTANCE, Addr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, pBuffer, Length, I2cxTimeout); /* Check the communication status */ @@ -699,3 +699,5 @@ uint32_t touch_read(void) { return 0; } + +void touch_wait_until_ready(void) {} diff --git a/core/embed/trezorhal/stm32f4/usb.c b/core/embed/trezorhal/stm32f4/usb.c index 0feaac1c1d2..7a6ab42c964 100644 --- a/core/embed/trezorhal/stm32f4/usb.c +++ b/core/embed/trezorhal/stm32f4/usb.c @@ -32,6 +32,8 @@ #define USB_PHY_ID USB_PHY_FS_ID #elif defined(USE_USB_HS) && defined(USE_USB_HS_IN_FS) #define USB_PHY_ID USB_PHY_HS_ID +#elif defined(USE_USB_HS) && !defined(USE_USB_HS_IN_FS) +#define USB_PHY_ID USB_PHY_HS_ID #else #error Unable to determine proper USB_PHY_ID to use #endif diff --git a/core/embed/trezorhal/stm32f4/usbd_conf.c b/core/embed/trezorhal/stm32f4/usbd_conf.c index c9b45e3df05..88ff109e061 100644 --- a/core/embed/trezorhal/stm32f4/usbd_conf.c +++ b/core/embed/trezorhal/stm32f4/usbd_conf.c @@ -83,6 +83,7 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) { GPIO_InitTypeDef GPIO_InitStruct; +#ifdef USB_OTG_FS if(hpcd->Instance == USB_OTG_FS) { /* Configure USB FS GPIOs */ @@ -93,10 +94,14 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; +#ifdef STM32U5 + GPIO_InitStruct.Alternate = GPIO_AF10_USB; +#else GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS; +#endif HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - /* Configure VBUS Pin */ + /* Configure VBUS Pin */ #if defined(MICROPY_HW_USB_VBUS_DETECT_PIN) // USB VBUS detect pin is always A9 GPIO_InitStruct.Pin = GPIO_PIN_9; @@ -118,15 +123,24 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USB FS Clocks */ __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); +#ifdef STM32U5 + + /* Enable VDDUSB */ + __HAL_RCC_PWR_CLK_ENABLE(); + HAL_PWREx_EnableVddUSB(); + __HAL_RCC_PWR_CLK_DISABLE(); + +#endif + /* Set USBFS Interrupt priority */ svc_setpriority(OTG_FS_IRQn, IRQ_PRI_OTG_FS); /* Enable USBFS Interrupt */ svc_enableIRQ(OTG_FS_IRQn); } +#endif #if defined(USE_USB_HS) - else if(hpcd->Instance == USB_OTG_HS) - { + if (hpcd->Instance == USB_OTG_HS) { #if defined(USE_USB_HS_IN_FS) /* Configure USB FS GPIOs */ @@ -168,7 +182,53 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) /* Enable USB HS Clocks */ __USB_OTG_HS_CLK_ENABLE(); -#else // !USE_USB_HS_IN_FS +#elif defined USE_USB_HS_INTERNAL_PHY && defined STM32U5 + + /* Configure DM and DP PINs */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + + GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12); + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF10_USB_HS; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + + __HAL_RCC_SYSCFG_CLK_ENABLE(); + + + /** Initializes the peripherals clock + */ + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USBPHY; + PeriphClkInit.UsbPhyClockSelection = RCC_USBPHYCLKSOURCE_HSE; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); + + /** Set the OTG PHY reference clock selection + */ + HAL_SYSCFG_SetOTGPHYReferenceClockSelection(SYSCFG_OTG_HS_PHY_CLK_SELECT_1); + + /* Peripheral clock enable */ + __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); + __HAL_RCC_USBPHYC_CLK_ENABLE(); + + /* Enable VDDUSB */ + __HAL_RCC_PWR_CLK_ENABLE(); + HAL_PWREx_EnableVddUSB(); + + /*configure VOSR register of USB*/ + HAL_PWREx_EnableUSBHSTranceiverSupply(); + __HAL_RCC_PWR_CLK_DISABLE(); + + + /*Configuring the SYSCFG registers OTG_HS PHY*/ + /*OTG_HS PHY enable*/ + HAL_SYSCFG_EnableOTGPHY(SYSCFG_OTG_HS_PHY_ENABLE); + + + +#else // !USE_USB_HS_IN_FS && !USE_USB_HS_INTERNAL_PHY /* Configure USB HS GPIOs */ __HAL_RCC_GPIOA_CLK_ENABLE(); @@ -242,20 +302,22 @@ void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd) */ void HAL_PCD_MspDeInit(PCD_HandleTypeDef *hpcd) { +#ifdef USB_OTG_FS if(hpcd->Instance == USB_OTG_FS) { /* Disable USB FS Clocks */ __HAL_RCC_USB_OTG_FS_CLK_DISABLE(); __HAL_RCC_SYSCFG_CLK_DISABLE(); } - #if defined(USE_USB_HS) - else if(hpcd->Instance == USB_OTG_HS) +#endif +#if defined(USE_USB_HS) + if(hpcd->Instance == USB_OTG_HS) { /* Disable USB FS Clocks */ __HAL_RCC_USB_OTG_HS_CLK_DISABLE(); __HAL_RCC_SYSCFG_CLK_DISABLE(); } - #endif +#endif } /******************************************************************************* @@ -440,6 +502,44 @@ USBD_StatusTypeDef USBD_LL_Init (USBD_HandleTypeDef *pdev) } } #endif +#if defined(USE_USB_HS) && !defined(USE_USB_HS_IN_FS) && defined STM32U5 + // Trezor T uses the OTG_HS peripheral + if (pdev->id == USB_PHY_HS_ID) { + /* Set LL Driver parameters */ + pcd_hs_handle.Instance = USB_OTG_HS; + pcd_hs_handle.Init.dev_endpoints = 6; + pcd_hs_handle.Init.use_dedicated_ep1 = 0; + pcd_hs_handle.Init.ep0_mps = 0x40; + pcd_hs_handle.Init.dma_enable = 0; + pcd_hs_handle.Init.low_power_enable = 0; + pcd_hs_handle.Init.phy_itface = USB_OTG_HS_EMBEDDED_PHY; + pcd_hs_handle.Init.Sof_enable = 1; + pcd_hs_handle.Init.speed = PCD_SPEED_HIGH; + // Trezor T hardware has PB13 connected to HS_VBUS + // but we leave vbus sensing disabled because + // we don't use it for anything. the device is a bus powered peripheral. + pcd_hs_handle.Init.vbus_sensing_enable = 0; + /* Link The driver to the stack */ + pcd_hs_handle.pData = pdev; + pdev->pData = &pcd_hs_handle; + /* Initialize LL Driver */ + HAL_PCD_Init(&pcd_hs_handle); + // the OTG_HS peripheral has a dedicated 4KiB data RAM from which we + // allocate an area for each transmit FIFO and the single shared receive FIFO. + // the configuration is in terms of 32-bit words, so we have 1024 32-bit words + // in this dedicated 4KiB data RAM to use. see section 35.10.1 and 34.11 in RM0090. + // the reference to section 34.11 is for the OTG_FS device, but the FIFO architecture + // diagram seems to apply similarly to the FIFO in the OTG_HS that we are using. + // USB packets that we deal with are 64 bytes in size which equates to 16 32-bit words. + // we size the transmit FIFO's equally and give the rest of the space to the receive FIFO. + const uint16_t transmit_fifo_size = 144; // 144 = 16 * 9 meaning that we give 9 packets of space for each transmit fifo + const uint16_t receive_fifo_zie = 160; // 160 = 1024 - 6 * 144 section 35.10.1 details what some of this is used for besides storing packets + HAL_PCDEx_SetRxFiFo(&pcd_hs_handle, receive_fifo_zie); + for (uint16_t i = 0; i < 6; i++) { + HAL_PCDEx_SetTxFiFo(&pcd_hs_handle, i, transmit_fifo_size); + } + } +#endif #if defined(USE_USB_HS_IN_FS) // Trezor T uses the OTG_HS peripheral if (pdev->id == USB_PHY_HS_ID) { @@ -676,7 +776,11 @@ void USBD_LL_Delay(uint32_t Delay) * @retval None */ #if defined(USE_USB_FS) +#ifdef STM32U5 +void OTG_HS_IRQHandler(void) { +#else void OTG_FS_IRQHandler(void) { +#endif SEGGER_SYSVIEW_RecordEnterISR(); IRQ_ENTER(OTG_FS_IRQn); if (pcd_fs_handle.Instance) { @@ -698,6 +802,7 @@ void OTG_HS_IRQHandler(void) { } #endif +#ifndef STM32U5 /** * @brief This function handles USB OTG Common FS/HS Wakeup functions. * @param *pcd_handle for FS or HS @@ -763,5 +868,6 @@ void OTG_HS_WKUP_IRQHandler(void) { IRQ_EXIT(OTG_HS_WKUP_IRQn); } #endif +#endif /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/core/embed/trezorhal/stm32f4/util.s b/core/embed/trezorhal/stm32f4/util.s index 5052206211b..30349678d93 100644 --- a/core/embed/trezorhal/stm32f4/util.s +++ b/core/embed/trezorhal/stm32f4/util.s @@ -167,4 +167,16 @@ shutdown_privileged: ldr r0, =0 b . // loop forever + .global MemManage_Handler + .type MemManage_Handler, STT_FUNC +MemManage_Handler: + ldr r2, =_sstack + mrs r1, msp + ldr r0, =_estack + msr msp, r0 + cmp r1, r2 + IT lt + bllt MemManage_Handler_SO + bl MemManage_Handler_MM + .end diff --git a/core/embed/trezorhal/stm32u5/backlight_pwm.c b/core/embed/trezorhal/stm32u5/backlight_pwm.c new file mode 120000 index 00000000000..ca21f1a602f --- /dev/null +++ b/core/embed/trezorhal/stm32u5/backlight_pwm.c @@ -0,0 +1 @@ +../stm32f4/backlight_pwm.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/backlight_pwm.h b/core/embed/trezorhal/stm32u5/backlight_pwm.h new file mode 120000 index 00000000000..37053b491dd --- /dev/null +++ b/core/embed/trezorhal/stm32u5/backlight_pwm.h @@ -0,0 +1 @@ +../stm32f4/backlight_pwm.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/board_capabilities.c b/core/embed/trezorhal/stm32u5/board_capabilities.c new file mode 120000 index 00000000000..da6d3b1a3d5 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/board_capabilities.c @@ -0,0 +1 @@ +../stm32f4/board_capabilities.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/boot_args.c b/core/embed/trezorhal/stm32u5/boot_args.c new file mode 120000 index 00000000000..ea7e8b6c203 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/boot_args.c @@ -0,0 +1 @@ +../stm32f4/boot_args.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/common.c b/core/embed/trezorhal/stm32u5/common.c new file mode 100644 index 00000000000..dfe50cfcd82 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/common.c @@ -0,0 +1,216 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include STM32_HAL_H + +#include + +#include "common.h" +#include "display.h" +#include "secret.h" +#include "terminal.h" +#ifdef FANCY_FATAL_ERROR +#include "rust_ui.h" +#endif +#include "flash_otp.h" +#include "model.h" +#include "platform.h" +#include "rand.h" +#include "supervise.h" + +#include "mini_printf.h" +#include "stm32u5xx_ll_utils.h" + +#ifdef RGB16 +#define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) +#else +#define COLOR_FATAL_ERROR COLOR_BLACK +#endif + +uint32_t systick_val_copy = 0; + +// from util.s +extern void shutdown_privileged(void); + +void __attribute__((noreturn)) trezor_shutdown(void) { + __HAL_RCC_SAES_CLK_DISABLE(); + // Erase all secrets + TAMP->CR2 |= TAMP_CR2_BKERASE; + +#ifdef USE_SVC_SHUTDOWN + svc_shutdown(); +#else + // It won't work properly unless called from the privileged mode + shutdown_privileged(); +#endif + + for (;;) + ; +} + +void __attribute__((noreturn)) +error_uni(const char *label, const char *msg, const char *footer) { + display_orientation(0); + +#ifdef FANCY_FATAL_ERROR + + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + if (label) { + term_printf("%s\n", label); + } + if (msg) { + term_printf("%s\n", msg); + } + if (footer) { + term_printf("\n%s\n", footer); + } +#endif + display_backlight(255); + display_refresh(); + trezor_shutdown(); +} + +void __attribute__((noreturn)) +__fatal_error(const char *expr, const char *msg, const char *file, int line, + const char *func) { + display_orientation(0); + display_backlight(255); + +#ifdef FANCY_FATAL_ERROR + char buf[256] = {0}; + mini_snprintf(buf, sizeof(buf), "%s: %d", file, line); + screen_fatal_error_rust("INTERNAL ERROR", msg != NULL ? msg : buf, + "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + term_printf("\nINTERNAL ERROR:\n"); + if (expr) { + term_printf("expr: %s\n", expr); + } + if (msg) { + term_printf("msg : %s\n", msg); + } + if (file) { + term_printf("file: %s:%d\n", file, line); + } + if (func) { + term_printf("func: %s\n", func); + } +#ifdef SCM_REVISION + const uint8_t *rev = (const uint8_t *)SCM_REVISION; + term_printf("rev : %02x%02x%02x%02x%02x\n", rev[0], rev[1], rev[2], rev[3], + rev[4]); +#endif + term_printf("\nPlease contact Trezor support.\n"); +#endif + trezor_shutdown(); +} + +void __attribute__((noreturn)) +error_shutdown(const char *label, const char *msg) { + display_orientation(0); + +#ifdef FANCY_FATAL_ERROR + + screen_fatal_error_rust(label, msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); + display_refresh(); +#else + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + if (label) { + term_printf("%s\n", label); + } + if (msg) { + term_printf("%s\n", msg); + } + term_printf("\nPLEASE VISIT TREZOR.IO/RSOD\n"); +#endif + display_backlight(255); + trezor_shutdown(); +} + +#ifndef NDEBUG +void __assert_func(const char *file, int line, const char *func, + const char *expr) { + __fatal_error(expr, "assert failed", file, line, func); +} +#endif + +void hal_delay(uint32_t ms) { HAL_Delay(ms); } +uint32_t hal_ticks_ms() { return HAL_GetTick(); } +void hal_delay_us(uint16_t delay_us) { + uint32_t val = svc_get_systick_val(); + uint32_t t = hal_ticks_ms() * 1000 + + (((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000)); + uint32_t t2 = t; + do { + val = svc_get_systick_val(); + t2 = hal_ticks_ms() * 1000 + + (((SystemCoreClock / 1000) - val) / (SystemCoreClock / 1000000)); + } while ((t2 - t) < delay_us); +} + +uint32_t __stack_chk_guard = 0; + +void __attribute__((noreturn)) __stack_chk_fail(void) { + error_shutdown("INTERNAL ERROR", "(SS)"); +} + +uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + +void collect_hw_entropy(void) { + // collect entropy from UUID + uint32_t w = LL_GetUID_Word0(); + memcpy(HW_ENTROPY_DATA, &w, 4); + w = LL_GetUID_Word1(); + memcpy(HW_ENTROPY_DATA + 4, &w, 4); + w = LL_GetUID_Word2(); + memcpy(HW_ENTROPY_DATA + 8, &w, 4); + + // set entropy in the OTP randomness block + if (secfalse == flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { + uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; + random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); + ensure(flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, + FLASH_OTP_BLOCK_SIZE), + NULL); + // ensure(flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS), NULL); + } + // collect entropy from OTP randomness block + ensure(flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12, + FLASH_OTP_BLOCK_SIZE), + NULL); +} + +// this function resets settings changed in one layer (bootloader/firmware), +// which might be incompatible with the other layers older versions, +// where this setting might be unknown +void ensure_compatible_settings(void) {} + +void show_wipe_code_screen(void) { + error_uni("WIPE CODE ENTERED", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); +} +void show_pin_too_many_screen(void) { + error_uni("TOO MANY PIN ATTEMPTS", "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); +} diff --git a/core/embed/trezorhal/stm32u5/displays/dsi.c b/core/embed/trezorhal/stm32u5/displays/dsi.c new file mode 100644 index 00000000000..cf31cf64095 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/dsi.c @@ -0,0 +1,1730 @@ +/** + ****************************************************************************** + * @file stm32u5x9j_discovery_lcd.c + * @author MCD Application Team + * @brief This file includes the driver for Liquid Crystal Display (LCD) + module + * mounted on MB1829A board (ARGB8888 color format). + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive directly in command mode a LCD TFT using the + DSI interface. + The following IPs are implied : DSI Host IP block working + in conjunction to the LTDC controller. + - This driver is linked by construction to LCD. + + 2. Driver description: + ---------------------- + + Initialization steps: + o Initialize the LCD using the BSP_LCD_Init() function. You can select + display orientation with "Orientation" parameter (portrait, landscape, + portrait with 180 degrees rotation or landscape with 180 degrees + rotation). + o Call BSP_LCD_GetXSize() and BSP_LCD_GetYsize() to get respectively + width and height in pixels of LCD in the current orientation. + o Call BSP_LCD_SetBrightness() and BSP_LCD_GetBrightness() to + respectively set and get LCD brightness. + o Call BSP_LCD_SetActiveLayer() to select the current active layer. + o Call BSP_LCD_GetFormat() to get LCD pixel format supported. + + + Display on LCD: + o Call BSP_LCD_DisplayOn() and BSP_LCD_DisplayOff() to respectively + switch on and switch off the LCD display. + o First, check that frame buffer is available using + BSP_LCD_IsFrameBufferAvailable(). o When frame buffer is available, modify it + using following functions: o Call BSP_LCD_WritePixel() and BSP_LCD_ReadPixel() + to respectively write and read a pixel. o Call BSP_LCD_DrawHLine() to draw a + horizontal line. o Call BSP_LCD_DrawVLine() to draw a vertical line. o Call + BSP_LCD_DrawBitmap() to draw a bitmap. o Call BSP_LCD_FillRect() to draw a + rectangle. o Call BSP_LCD_FillRGBRect() to draw a rectangle with RGB buffer. + o Call BSP_LCD_Refresh() to refresh LCD display. + + + De-initialization steps: + o De-initialize the LCD using the BSP_LCD_DeInit() function. + + @endverbatim + ****************************************************************************** + * @attention + * + * Copyright (c) 2023 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "colors.h" +#include "stdint.h" +#include "string.h" +#include STM32_HAL_H + +/* Common Error codes */ +#define BSP_ERROR_NONE 0 +#define BSP_ERROR_NO_INIT -1 +#define BSP_ERROR_WRONG_PARAM -2 +#define BSP_ERROR_BUSY -3 +#define BSP_ERROR_PERIPH_FAILURE -4 +#define BSP_ERROR_COMPONENT_FAILURE -5 +#define BSP_ERROR_UNKNOWN_FAILURE -6 +#define BSP_ERROR_UNKNOWN_COMPONENT -7 +#define BSP_ERROR_BUS_FAILURE -8 +#define BSP_ERROR_CLOCK_FAILURE -9 +#define BSP_ERROR_MSP_FAILURE -10 +#define BSP_ERROR_FEATURE_NOT_SUPPORTED -11 + +#define BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE (-102) +/* Button user interrupt priority */ +#define BSP_BUTTON_USER_IT_PRIORITY \ + 0x0FUL /* Default is lowest priority level */ + +/* LCD interrupt priorities */ +#define BSP_LCD_GFXMMU_IT_PRIORITY \ + 0x0FUL /* Default is lowest priority level \ + */ +#define BSP_LCD_LTDC_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ +#define BSP_LCD_DSI_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ + +/* HSPI RAM interrupt priority */ +#define BSP_HSPI_RAM_IT_PRIORITY 0x0FUL /* Default is lowest priority level */ +#define LCD_PIXEL_FORMAT_ARGB8888 \ + 0x00000000U /*!< ARGB8888 LTDC pixel format \ + */ +#define LCD_PIXEL_FORMAT_RGB888 0x00000001U /*!< RGB888 LTDC pixel format */ +#define LCD_PIXEL_FORMAT_RGB565 0x00000002U /*!< RGB565 LTDC pixel format */ +#define LCD_PIXEL_FORMAT_ARGB1555 \ + 0x00000003U /*!< ARGB1555 LTDC pixel format \ + */ +#define LCD_PIXEL_FORMAT_ARGB4444 \ + 0x00000004U /*!< ARGB4444 LTDC pixel format \ + */ +#define LCD_PIXEL_FORMAT_L8 0x00000005U /*!< L8 LTDC pixel format */ +#define LCD_PIXEL_FORMAT_AL44 0x00000006U /*!< AL44 LTDC pixel format */ +#define LCD_PIXEL_FORMAT_AL88 0x00000007U /*!< AL88 LTDC pixel format */ +/* LCD instances */ +#define LCD_INSTANCES_NBR 1U + +/* LCD orientations */ +#define LCD_ORIENTATION_PORTRAIT 0U +#define LCD_ORIENTATION_LANDSCAPE 1U +#define LCD_ORIENTATION_PORTRAIT_ROT180 2U +#define LCD_ORIENTATION_LANDSCAPE_ROT180 3U + +#define DSI_POWERON_GPIO_PORT GPIOI +#define DSI_POWERON_GPIO_PIN GPIO_PIN_5 +#define DSI_POWERON_GPIO_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE() + +#define DSI_RESET_GPIO_PORT GPIOD +#define DSI_RESET_GPIO_PIN GPIO_PIN_5 +#define DSI_RESET_GPIO_CLOCK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() + +#define VSYNC 1 +#define VBP 12 +#define VFP 50 +#define VACT 481 +#define HSYNC 2 +#define HBP 1 +#define HFP 1 +#define HACT 480 +#define LCD_WIDTH 480 +#define LCD_HEIGHT 480 + +#define PIXEL_PER_LINE 768U +#define BYTE_PER_PIXEL 4U /* ARGB8888 */ + +#include "gfxmmu_lut.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32U5x9J_DISCOVERY + * @{ + */ + +/** @defgroup STM32U5x9J_DISCOVERY_LCD LCD + * @{ + */ + +/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Defines LCD Private Constants + * @{ + */ + +/** + * @} + */ + +/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Variables LCD Private Variables + * @{ + */ + +__attribute__((section(".fb1"))) +ALIGN_32BYTES(uint32_t PhysFrameBuffer0[184320]); +__attribute__((section(".fb2"))) +ALIGN_32BYTES(uint32_t PhysFrameBuffer1[184320]); + +__attribute__((section(".gfxmmu_table"))) +uint32_t gfxmmu_lut[2 * GFXMMU_LUT_SIZE]; +__attribute__((section(".framebuffer_select"))) uint32_t act_frame_buffer = 0; + +#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1) +static uint32_t LcdGfxmmu_IsMspCbValid[LCD_INSTANCES_NBR] = {0}; +#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1) */ + +#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1) +static uint32_t LcdLtdc_IsMspCbValid[LCD_INSTANCES_NBR] = {0}; +#endif /* (USE_HAL_LTDC_REGISTER_CALLBACKS == 1) */ + +#if (USE_HAL_DSI_REGISTER_CALLBACKS == 1) +static uint32_t LcdDsi_IsMspCbValid[LCD_INSTANCES_NBR] = {0}; +#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 1) */ + +GFXMMU_HandleTypeDef hlcd_gfxmmu = {0}; +LTDC_HandleTypeDef hlcd_ltdc = {0}; +DSI_HandleTypeDef hlcd_dsi = {0}; +static DSI_VidCfgTypeDef DSIVidCfg = {0}; + +uint16_t window_x0 = 0; +uint16_t window_y0 = 0; +uint16_t window_x1 = 0; +uint16_t window_y1 = 0; +uint16_t cursor_x = 0; +uint16_t cursor_y = 0; + +/** + * @} + */ + +/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_FunctionPrototypes LCD Private + * Function Prototypes + * @{ + */ +static int32_t LCD_Init(void); +static int32_t LCD_DeInit(void); + +static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu); +static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu); +static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc); +static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc); +static void DSI_MspInit(DSI_HandleTypeDef *hdsi); +static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi); +#if (USE_HAL_DSI_REGISTER_CALLBACKS == 1) +static void DSI_EndOfRefreshCallback(DSI_HandleTypeDef *hdsi); +#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 1) */ +/** + * @} + */ + +/** @addtogroup STM32U5x9J_DISCOVERY_LCD_Exported_Functions + * @{ + */ +/** + * @brief Initialize the LCD. + * @param Instance LCD Instance. + * @param Orientation LCD_ORIENTATION_PORTRAIT, LCD_ORIENTATION_LANDSCAPE, + * LCD_ORIENTATION_PORTRAIT_ROT180 or + * LCD_ORIENTATION_LANDSCAPE_ROT180. + * @retval BSP status. + */ +int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation) { + int32_t status = BSP_ERROR_NONE; + + if ((Instance >= LCD_INSTANCES_NBR) || + (Orientation > LCD_ORIENTATION_LANDSCAPE_ROT180)) { + status = BSP_ERROR_WRONG_PARAM; + } else if ((Orientation == LCD_ORIENTATION_LANDSCAPE) || + (Orientation == LCD_ORIENTATION_LANDSCAPE_ROT180)) { + status = BSP_ERROR_FEATURE_NOT_SUPPORTED; + } else { + if (LCD_Init() != 0) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } + + return status; +} + +/** + * @brief De-Initialize the LCD. + * @param Instance LCD Instance. + * @retval BSP status. + */ +int32_t BSP_LCD_DeInit(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + if (LCD_DeInit() != 0) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } + + return status; +} + +/** + * @brief Set the display on. + * @param Instance LCD Instance. + * @retval BSP status. + */ +int32_t BSP_LCD_DisplayOn(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Set the display on */ + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, + DSI_SET_DISPLAY_ON, 0x00) != HAL_OK) { + status = BSP_ERROR_WRONG_PARAM; + } + } + + return status; +} + +/** + * @brief Set the display off. + * @param Instance LCD Instance. + * @retval BSP status. + */ +int32_t BSP_LCD_DisplayOff(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Set the display off */ + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, + DSI_SET_DISPLAY_OFF, 0x00) != HAL_OK) { + status = BSP_ERROR_WRONG_PARAM; + } + } + + return status; +} + +/** + * @brief Set the display brightness. + * @param Instance LCD Instance. + * @param Brightness [00: Min (black), 100 Max]. + * @retval BSP status. + */ +int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness) { + int32_t status; + + if ((Instance >= LCD_INSTANCES_NBR) || (Brightness > 100U)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + status = BSP_ERROR_FEATURE_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief Get the display brightness. + * @param Instance LCD Instance. + * @param Brightness [00: Min (black), 100 Max]. + * @retval BSP status. + */ +int32_t BSP_LCD_GetBrightness(uint32_t Instance, uint32_t *Brightness) { + int32_t status; + + if ((Instance >= LCD_INSTANCES_NBR) || (Brightness == NULL)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + status = BSP_ERROR_FEATURE_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief Get the LCD X size. + * @param Instance LCD Instance. + * @param Xsize LCD X size. + * @retval BSP status. + */ +int32_t BSP_LCD_GetXSize(uint32_t Instance, uint32_t *Xsize) { + int32_t status = BSP_ERROR_NONE; + + if ((Instance >= LCD_INSTANCES_NBR) || (Xsize == NULL)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Get the display Xsize */ + *Xsize = LCD_WIDTH; + } + + return status; +} + +/** + * @brief Get the LCD Y size. + * @param Instance LCD Instance. + * @param Ysize LCD Y size. + * @retval BSP status. + */ +int32_t BSP_LCD_GetYSize(uint32_t Instance, uint32_t *Ysize) { + int32_t status = BSP_ERROR_NONE; + + if ((Instance >= LCD_INSTANCES_NBR) || (Ysize == NULL)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Get the display Ysize */ + *Ysize = LCD_HEIGHT; + } + + return status; +} + +/** + * @brief Set the LCD active layer. + * @param Instance LCD Instance. + * @param LayerIndex Active layer index. + * @retval BSP status. + */ +int32_t BSP_LCD_SetActiveLayer(uint32_t Instance, uint32_t LayerIndex) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Nothing to do */ + UNUSED(LayerIndex); + } + + return status; +} + +/** + * @brief Get pixel format supported by LCD. + * @param Instance LCD Instance. + * @param Format Pointer on pixel format. + * @retval BSP status. + */ +int32_t BSP_LCD_GetFormat(uint32_t Instance, uint32_t *Format) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Get pixel format supported by LCD */ + *Format = LCD_PIXEL_FORMAT_ARGB8888; + } + + return status; +} + +void MX_GFXMMU_Reinit(GFXMMU_HandleTypeDef *hgfxmmu) { + /* Initialize GFXMMU */ + hgfxmmu->Instance = GFXMMU; + hgfxmmu->Init.BlocksPerLine = GFXMMU_192BLOCKS; + hgfxmmu->Init.DefaultValue = 0xFFFFFFFFU; + hgfxmmu->Init.Buffers.Buf0Address = (uint32_t)PhysFrameBuffer0; + hgfxmmu->Init.Buffers.Buf1Address = (uint32_t)PhysFrameBuffer1; + hgfxmmu->Init.Buffers.Buf2Address = 0; + hgfxmmu->Init.Buffers.Buf3Address = 0; +#if defined(GFXMMU_CR_CE) + hgfxmmu->Init.CachePrefetch.Activation = DISABLE; + hgfxmmu->Init.CachePrefetch.CacheLock = GFXMMU_CACHE_LOCK_DISABLE; + hgfxmmu->Init.CachePrefetch.CacheLockBuffer = + GFXMMU_CACHE_LOCK_BUFFER0; /* NU */ + hgfxmmu->Init.CachePrefetch.CacheForce = GFXMMU_CACHE_FORCE_ENABLE; /* NU */ + hgfxmmu->Init.CachePrefetch.OutterBufferability = + GFXMMU_OUTTER_BUFFERABILITY_DISABLE; + hgfxmmu->Init.CachePrefetch.OutterCachability = + GFXMMU_OUTTER_CACHABILITY_DISABLE; + hgfxmmu->Init.CachePrefetch.Prefetch = GFXMMU_PREFETCH_DISABLE; +#endif /* GFXMMU_CR_CE */ +#if defined(GFXMMU_CR_ACE) + hgfxmmu->Init.AddressCache.Activation = DISABLE; + hgfxmmu->Init.AddressCache.AddressCacheLockBuffer = + GFXMMU_ADDRESSCACHE_LOCK_BUFFER0; +#endif /* GFXMMU_CR_ACE */ + hgfxmmu->Init.Interrupts.Activation = DISABLE; + hgfxmmu->Init.Interrupts.UsedInterrupts = GFXMMU_AHB_MASTER_ERROR_IT; /* NU */ +} + +/** + * @brief MX GFXMMU initialization. + * @param hgfxmmu GFXMMU handle. + * @retval HAL status. + */ +__weak HAL_StatusTypeDef MX_GFXMMU_Init(GFXMMU_HandleTypeDef *hgfxmmu) { + MX_GFXMMU_Reinit(hgfxmmu); + return HAL_GFXMMU_Init(hgfxmmu); +} + +/** + * @brief MX LTDC clock configuration. + * @param hltdc LTDC handle. + * @retval HAL status. + */ +__weak HAL_StatusTypeDef MX_LTDC_ClockConfig(LTDC_HandleTypeDef *hltdc) { + RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0}; + + /* Prevent unused argument(s) compilation warning */ + UNUSED(hltdc); + + /* Start and configurre PLL3 */ + /* HSE = 16MHZ */ + /* 16/(M=4) = 4MHz input (min) */ + /* 4*(N=125) = 500MHz VCO (almost max) */ + /* 500/(P=8) = 62.5 for DSI ie exactly the lane byte clock*/ + /* 500/(R=24) = 20.83 for LTDC exact match with DSI bandwidth */ + PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + PLL3InitPeriph.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3; + PLL3InitPeriph.PLL3.PLL3M = 4; + PLL3InitPeriph.PLL3.PLL3N = 125; + PLL3InitPeriph.PLL3.PLL3P = 8; + PLL3InitPeriph.PLL3.PLL3Q = 8; + PLL3InitPeriph.PLL3.PLL3R = 24; + PLL3InitPeriph.PLL3.PLL3FRACN = 0; + PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1; + PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP; + PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; + return HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph); +} + +void MX_LTDC_Reinit(LTDC_HandleTypeDef *hltdc) { + /* LTDC initialization */ + hltdc->Instance = LTDC; + hltdc->Init.HSPolarity = LTDC_HSPOLARITY_AL; + hltdc->Init.VSPolarity = LTDC_VSPOLARITY_AL; + hltdc->Init.DEPolarity = LTDC_DEPOLARITY_AL; + hltdc->Init.PCPolarity = LTDC_PCPOLARITY_IPC; + hltdc->Init.HorizontalSync = HSYNC - 1; + hltdc->Init.AccumulatedHBP = HSYNC + HBP - 1; + hltdc->Init.AccumulatedActiveW = HACT + HBP + HSYNC - 1; + hltdc->Init.TotalWidth = HACT + HBP + HFP + HSYNC - 1; + hltdc->Init.Backcolor.Red = 0; /* Not used default value */ + hltdc->Init.Backcolor.Green = 0; /* Not used default value */ + hltdc->Init.Backcolor.Blue = 0; /* Not used default value */ + hltdc->Init.Backcolor.Reserved = 0xFF; + + HAL_LTDCEx_StructInitFromVideoConfig(&hlcd_ltdc, &DSIVidCfg); +} + +/** + * @brief MX LTDC initialization. + * @param hltdc LTDC handle. + * @retval HAL status. + */ +__weak HAL_StatusTypeDef MX_LTDC_Init(LTDC_HandleTypeDef *hltdc) { + MX_LTDC_Reinit(hltdc); + + return HAL_LTDC_Init(hltdc); +} + +// HAL_StatusTypeDef MX_LTDC_ReConfigLayer(LTDC_HandleTypeDef *hltdc, uint32_t +// LayerIndex) +//{ +// LTDC_LayerCfgTypeDef LayerCfg = {0}; +// +///* LTDC layer configuration */ +// LayerCfg.WindowX0 = 0; +// LayerCfg.WindowX1 = LCD_WIDTH; +// LayerCfg.WindowY0 = 1; +// LayerCfg.WindowY1 = (uint32_t)LCD_HEIGHT + 1UL; +// LayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; +// LayerCfg.Alpha = 0xFF; /* NU default value */ +// LayerCfg.Alpha0 = 0; /* NU default value */ +// LayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default +// value */ LayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; /* Not +// Used: default value */ LayerCfg.FBStartAdress = +// GFXMMU_VIRTUAL_BUFFER0_BASE; LayerCfg.ImageWidth = PIXEL_PER_LINE; /* +// Number of pixels per line in virtual frame buffer */ LayerCfg.ImageHeight = +// LCD_HEIGHT; LayerCfg.Backcolor.Red = 0; /* Not Used: default value */ +// LayerCfg.Backcolor.Green = 0; /* Not Used: default value */ +// LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */ +// LayerCfg.Bac +// return HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LayerIndex);kcolor.Reserved = +// 0xFF; +//} + +/** + * @brief MX LTDC layer configuration. + * @param hltdc LTDC handle. + * @param LayerIndex LTDC layer index. + * @retval HAL status. + */ +__weak HAL_StatusTypeDef MX_LTDC_ConfigLayer(LTDC_HandleTypeDef *hltdc, + uint32_t LayerIndex, + uint32_t fb_addr) { + LTDC_LayerCfgTypeDef LayerCfg = {0}; + + /* LTDC layer configuration */ + LayerCfg.WindowX0 = 0; + LayerCfg.WindowX1 = LCD_WIDTH; + LayerCfg.WindowY0 = 1; + LayerCfg.WindowY1 = (uint32_t)LCD_HEIGHT + 1UL; + LayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888; + LayerCfg.Alpha = 0xFF; /* NU default value */ + LayerCfg.Alpha0 = 0; /* NU default value */ + LayerCfg.BlendingFactor1 = + LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default value */ + LayerCfg.BlendingFactor2 = + LTDC_BLENDING_FACTOR2_PAxCA; /* Not Used: default value */ + LayerCfg.FBStartAdress = fb_addr; + LayerCfg.ImageWidth = + PIXEL_PER_LINE; /* Number of pixels per line in virtual frame buffer */ + LayerCfg.ImageHeight = LCD_HEIGHT; + LayerCfg.Backcolor.Red = 0; /* Not Used: default value */ + LayerCfg.Backcolor.Green = 0; /* Not Used: default value */ + LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */ + LayerCfg.Backcolor.Reserved = 0xFF; + return HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LayerIndex); +} + +/** + * @brief MX DSI initialization. + * @param hdsi DSI handle. + * @retval HAL status. + */ +HAL_StatusTypeDef MX_DSI_Reinit(DSI_HandleTypeDef *hdsi) { + /* DSI initialization */ + hdsi->Instance = DSI; + hdsi->Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE; + /* We have 1 data lane at 500Mbps => lane byte clock at 500/8 = 62,5 MHZ */ + /* We want TX escape clock at around 20MHz and under 20MHz so clock division + * is set to 4 */ + hdsi->Init.TXEscapeCkdiv = 4; + hdsi->Init.NumberOfLanes = DSI_TWO_DATA_LANES; + hdsi->Init.PHYFrequencyRange = DSI_DPHY_FRANGE_450MHZ_510MHZ; + hdsi->Init.PHYLowPowerOffset = 0; + + /* Configure the DSI for Video mode */ + DSIVidCfg.VirtualChannelID = 0; + DSIVidCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH; + DSIVidCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH; + DSIVidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; + DSIVidCfg.ColorCoding = DSI_RGB888; + DSIVidCfg.Mode = DSI_VID_MODE_BURST; + DSIVidCfg.PacketSize = LCD_WIDTH; + DSIVidCfg.NullPacketSize = 0xFFFU; + DSIVidCfg.HorizontalSyncActive = HSYNC * 3; + DSIVidCfg.HorizontalBackPorch = HBP * 3; + DSIVidCfg.HorizontalLine = (HACT + HSYNC + HBP + HFP) * 3; + DSIVidCfg.VerticalSyncActive = VSYNC; + DSIVidCfg.VerticalBackPorch = VBP; + DSIVidCfg.VerticalFrontPorch = VFP; + DSIVidCfg.VerticalActive = VACT; + DSIVidCfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE; + DSIVidCfg.LPLargestPacketSize = 64; + /* Specify for each region of the video frame, if the transmission of command + * in LP mode is allowed in this region */ + /* while streaming is active in video mode */ + DSIVidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE; + DSIVidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE; + DSIVidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE; + DSIVidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE; + DSIVidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE; + DSIVidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; + DSIVidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_ENABLE; + DSIVidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE; + + return HAL_OK; +} + +/** + * @brief MX DSI initialization. + * @param hdsi DSI handle. + * @retval HAL status. + */ +__weak HAL_StatusTypeDef MX_DSI_Init(DSI_HandleTypeDef *hdsi) { + DSI_PLLInitTypeDef PLLInit = {0}; + + /* DSI initialization */ + hdsi->Instance = DSI; + hdsi->Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE; + /* We have 1 data lane at 500Mbps => lane byte clock at 500/8 = 62,5 MHZ */ + /* We want TX escape clock at around 20MHz and under 20MHz so clock division + * is set to 4 */ + hdsi->Init.TXEscapeCkdiv = 4; + hdsi->Init.NumberOfLanes = DSI_TWO_DATA_LANES; + hdsi->Init.PHYFrequencyRange = DSI_DPHY_FRANGE_450MHZ_510MHZ; + hdsi->Init.PHYLowPowerOffset = 0; + + PLLInit.PLLNDIV = 125; + PLLInit.PLLIDF = 4; + PLLInit.PLLODF = 2; + PLLInit.PLLVCORange = DSI_DPHY_VCO_FRANGE_800MHZ_1GHZ; + PLLInit.PLLChargePump = DSI_PLL_CHARGE_PUMP_2000HZ_4400HZ; + PLLInit.PLLTuning = DSI_PLL_LOOP_FILTER_2000HZ_4400HZ; + + if (HAL_DSI_Init(hdsi, &PLLInit) != HAL_OK) { + return HAL_ERROR; + } + + if (HAL_DSI_SetGenericVCID(&hlcd_dsi, 0) != HAL_OK) { + return HAL_ERROR; + } + + /* Configure the DSI for Video mode */ + DSIVidCfg.VirtualChannelID = 0; + DSIVidCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH; + DSIVidCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH; + DSIVidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH; + DSIVidCfg.ColorCoding = DSI_RGB888; + DSIVidCfg.Mode = DSI_VID_MODE_BURST; + DSIVidCfg.PacketSize = LCD_WIDTH; + DSIVidCfg.NullPacketSize = 0xFFFU; + DSIVidCfg.HorizontalSyncActive = HSYNC * 3; + DSIVidCfg.HorizontalBackPorch = HBP * 3; + DSIVidCfg.HorizontalLine = (HACT + HSYNC + HBP + HFP) * 3; + DSIVidCfg.VerticalSyncActive = VSYNC; + DSIVidCfg.VerticalBackPorch = VBP; + DSIVidCfg.VerticalFrontPorch = VFP; + DSIVidCfg.VerticalActive = VACT; + DSIVidCfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE; + DSIVidCfg.LPLargestPacketSize = 64; + /* Specify for each region of the video frame, if the transmission of command + * in LP mode is allowed in this region */ + /* while streaming is active in video mode */ + DSIVidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE; + DSIVidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE; + DSIVidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE; + DSIVidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE; + DSIVidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE; + DSIVidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE; + DSIVidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_ENABLE; + DSIVidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE; + + /* Drive the display */ + if (HAL_DSI_ConfigVideoMode(&hlcd_dsi, &DSIVidCfg) != HAL_OK) { + return HAL_ERROR; + } + + return HAL_OK; +} + +/** + * @brief MX DMA2D initialization. + * @param hdma2d DMA2D handle. + * @param Mode DMA2D transfer mode. + * @param OffLine DMA2D output offset. + * @retval HAL status. + */ +__weak HAL_StatusTypeDef MX_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d, + uint32_t Mode, uint32_t OffLine) { + /* Register to memory mode with ARGB8888 as color Mode */ + hdma2d->Instance = DMA2D; + hdma2d->Init.Mode = Mode; + hdma2d->Init.ColorMode = DMA2D_OUTPUT_ARGB8888; + hdma2d->Init.OutputOffset = OffLine; + hdma2d->Init.AlphaInverted = DMA2D_REGULAR_ALPHA; + hdma2d->Init.RedBlueSwap = DMA2D_RB_REGULAR; + hdma2d->Init.BytesSwap = DMA2D_BYTES_REGULAR; + hdma2d->Init.LineOffsetMode = DMA2D_LOM_PIXELS; + + /* DMA2D Initialization */ + return HAL_DMA2D_Init(hdma2d); +} + +#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1) +/** + * @brief Register Default LCD GFXMMU Msp Callbacks + * @retval BSP status + */ +int32_t BSP_LCD_GFXMMU_RegisterDefaultMspCallbacks(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_GFXMMU_RESET_HANDLE_STATE(&hlcd_gfxmmu); + + /* Register default MspInit/MspDeInit Callback */ + if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, HAL_GFXMMU_MSPINIT_CB_ID, + GFXMMU_MspInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, + HAL_GFXMMU_MSPDEINIT_CB_ID, + GFXMMU_MspDeInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdGfxmmu_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} + +/** + * @brief Register LCD GFXMMU Msp Callback + * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions + * @retval BSP status + */ +int32_t BSP_LCD_GFXMMU_RegisterMspCallbacks(uint32_t Instance, + BSP_LCD_GFXMMU_Cb_t *Callback) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_GFXMMU_RESET_HANDLE_STATE(&hlcd_gfxmmu); + + /* Register MspInit/MspDeInit Callbacks */ + if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, HAL_GFXMMU_MSPINIT_CB_ID, + Callback->pMspGfxmmuInitCb) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_GFXMMU_RegisterCallback( + &hlcd_gfxmmu, HAL_GFXMMU_MSPDEINIT_CB_ID, + Callback->pMspGfxmmuDeInitCb) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdGfxmmu_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} +#endif /* USE_HAL_GFXMMU_REGISTER_CALLBACKS */ + +#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1) +/** + * @brief Register Default LCD LTDC Msp Callbacks + * @retval BSP status + */ +int32_t BSP_LCD_LTDC_RegisterDefaultMspCallbacks(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_LTDC_RESET_HANDLE_STATE(&hlcd_ltdc); + + /* Register default MspInit/MspDeInit Callback */ + if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPINIT_CB_ID, + LTDC_MspInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPDEINIT_CB_ID, + LTDC_MspDeInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdLtdc_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} + +/** + * @brief Register LCD LTDC Msp Callback + * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions + * @retval BSP status + */ +int32_t BSP_LCD_LTDC_RegisterMspCallbacks(uint32_t Instance, + BSP_LCD_LTDC_Cb_t *Callback) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_LTDC_RESET_HANDLE_STATE(&hlcd_ltdc); + + /* Register MspInit/MspDeInit Callbacks */ + if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPINIT_CB_ID, + Callback->pMspLtdcInitCb) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPDEINIT_CB_ID, + Callback->pMspLtdcDeInitCb) != + HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdLtdc_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} +#endif /* USE_HAL_LTDC_REGISTER_CALLBACKS */ + +#if (USE_HAL_DSI_REGISTER_CALLBACKS == 1) +/** + * @brief Register Default LCD DSI Msp Callbacks + * @retval BSP status + */ +int32_t BSP_LCD_DSI_RegisterDefaultMspCallbacks(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_DSI_RESET_HANDLE_STATE(&hlcd_dsi); + + /* Register default MspInit/MspDeInit Callback */ + if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPINIT_CB_ID, + DSI_MspInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPDEINIT_CB_ID, + DSI_MspDeInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdDsi_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} + +/** + * @brief Register LCD DSI Msp Callback + * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions + * @retval BSP status + */ +int32_t BSP_LCD_DSI_RegisterMspCallbacks(uint32_t Instance, + BSP_LCD_DSI_Cb_t *Callback) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_DSI_RESET_HANDLE_STATE(&hlcd_dsi); + + /* Register MspInit/MspDeInit Callbacks */ + if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPINIT_CB_ID, + Callback->pMspDsiInitCb) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPDEINIT_CB_ID, + Callback->pMspDsiDeInitCb) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdDsi_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} +#endif /* USE_HAL_DSI_REGISTER_CALLBACKS */ + +#if (USE_HAL_DMA2D_REGISTER_CALLBACKS == 1) +/** + * @brief Register Default LCD DMA2D Msp Callbacks + * @retval BSP status + */ +int32_t BSP_LCD_DMA2D_RegisterDefaultMspCallbacks(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_DMA2D_RESET_HANDLE_STATE(&hlcd_dma2d); + + /* Register default MspInit/MspDeInit Callback */ + if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, HAL_DMA2D_MSPINIT_CB_ID, + DMA2D_MspInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, + HAL_DMA2D_MSPDEINIT_CB_ID, + DMA2D_MspDeInit) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdDma2d_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} + +/** + * @brief Register LCD DMA2D Msp Callback + * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions + * @retval BSP status + */ +int32_t BSP_LCD_DMA2D_RegisterMspCallbacks(uint32_t Instance, + BSP_LCD_DMA2D_Cb_t *Callback) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + __HAL_DMA2D_RESET_HANDLE_STATE(&hlcd_dma2d); + + /* Register MspInit/MspDeInit Callbacks */ + if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, HAL_DMA2D_MSPINIT_CB_ID, + Callback->pMspDma2dInitCb) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else if (HAL_DMA2D_RegisterCallback( + &hlcd_dma2d, HAL_DMA2D_MSPDEINIT_CB_ID, + Callback->pMspDma2dDeInitCb) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + LcdDma2d_IsMspCbValid[Instance] = 1U; + } + } + + /* BSP status */ + return status; +} +#endif /* USE_HAL_DMA2D_REGISTER_CALLBACKS */ +/** + * @} + */ + +/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Functions LCD Private Functions + * @{ + */ + +/** + * @brief Initialize LCD. + * @retval BSP status. + */ +static int32_t LCD_Init(void) { + int32_t status = BSP_ERROR_NONE; + uint32_t ErrorNumber = 0; + DSI_PHY_TimerTypeDef PhyTimers = {0}; + DSI_HOST_TimeoutTypeDef HostTimeouts = {0}; + + /***************/ + /* GFXMMU init */ + /***************/ +#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) + GFXMMU_MspInit(&hlcd_gfxmmu); +#else + /* Register the GFXMMU MSP Callbacks */ + if (LcdGfxmmu_IsMspCbValid[0] == 0U) { + if (BSP_LCD_GFXMMU_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } +#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */ + + if (status == BSP_ERROR_NONE) { + /* GFXMMU peripheral initialization */ + if (MX_GFXMMU_Init(&hlcd_gfxmmu) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } + /* Initialize LUT */ + else if (HAL_GFXMMU_ConfigLut(&hlcd_gfxmmu, 0, LCD_WIDTH, + (uint32_t)&gfxmmu_lut) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + /* Disable non visible lines : from line 480 to 1023 */ + if (HAL_OK != HAL_GFXMMU_DisableLutLines(&hlcd_gfxmmu, LCD_WIDTH, 544)) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } + } + + /************/ + /* DSI init */ + /************/ + if (status == BSP_ERROR_NONE) { +#if (USE_HAL_DSI_REGISTER_CALLBACKS == 0) + DSI_MspInit(&hlcd_dsi); +#else + /* Register the DSI MSP Callbacks */ + if (LcdDsi_IsMspCbValid[0] == 0U) { + if (BSP_LCD_DSI_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } +#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 0) */ + + if (status == BSP_ERROR_NONE) { + /* DSI peripheral initialization */ + if (MX_DSI_Init(&hlcd_dsi) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } + } + + /*********************/ + /* LCD configuration */ + /*********************/ + if (status == BSP_ERROR_NONE) { + PhyTimers.ClockLaneHS2LPTime = 11; + PhyTimers.ClockLaneLP2HSTime = 40; + PhyTimers.DataLaneHS2LPTime = 12; + PhyTimers.DataLaneLP2HSTime = 23; + PhyTimers.DataLaneMaxReadTime = 0; + PhyTimers.StopWaitTime = 7; + + if (HAL_DSI_ConfigPhyTimer(&hlcd_dsi, &PhyTimers) != HAL_OK) { + return 6; + } + + HostTimeouts.TimeoutCkdiv = 1; + HostTimeouts.HighSpeedTransmissionTimeout = 0; + HostTimeouts.LowPowerReceptionTimeout = 0; + HostTimeouts.HighSpeedReadTimeout = 0; + HostTimeouts.LowPowerReadTimeout = 0; + HostTimeouts.HighSpeedWriteTimeout = 0; + HostTimeouts.HighSpeedWritePrespMode = 0; + HostTimeouts.LowPowerWriteTimeout = 0; + HostTimeouts.BTATimeout = 0; + + if (HAL_DSI_ConfigHostTimeouts(&hlcd_dsi, &HostTimeouts) != HAL_OK) { + return 7; + } + + if (HAL_DSI_ConfigFlowControl(&hlcd_dsi, DSI_FLOW_CONTROL_BTA) != HAL_OK) { + return 7; + } + + /* Enable the DSI host */ + __HAL_DSI_ENABLE(&hlcd_dsi); + + /*************/ + /* LTDC init */ + /*************/ + if (status == BSP_ERROR_NONE) { + if (MX_LTDC_ClockConfig(&hlcd_ltdc) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { +#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 0) + LTDC_MspInit(&hlcd_ltdc); +#else + /* Register the LTDC MSP Callbacks */ + if (LcdLtdc_IsMspCbValid[0] == 0U) { + if (BSP_LCD_LTDC_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } +#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */ + + if (status == BSP_ERROR_NONE) { + /* LTDC peripheral initialization */ + if (MX_LTDC_Init(&hlcd_ltdc) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } else { + if (MX_LTDC_ConfigLayer(&hlcd_ltdc, LTDC_LAYER_1, + GFXMMU_VIRTUAL_BUFFER0_BASE_S) != HAL_OK) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } + } + } + } + + /* Start DSI */ + if (HAL_DSI_Start(&(hlcd_dsi)) != HAL_OK) { + return 8; + } + + /* CMD Mode */ + uint8_t InitParam1[3] = {0xFF, 0x83, 0x79}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB9, + InitParam1) != HAL_OK) { + ErrorNumber++; + } + + /* SETPOWER */ + uint8_t InitParam2[16] = {0x44, 0x1C, 0x1C, 0x37, 0x57, 0x90, 0xD0, 0xE2, + 0x58, 0x80, 0x38, 0x38, 0xF8, 0x33, 0x34, 0x42}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 16, 0xB1, + InitParam2) != HAL_OK) { + ErrorNumber++; + } + + /* SETDISP */ + uint8_t InitParam3[9] = {0x80, 0x14, 0x0C, 0x30, 0x20, + 0x50, 0x11, 0x42, 0x1D}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 9, 0xB2, + InitParam3) != HAL_OK) { + ErrorNumber++; + } + + /* Set display cycle timing */ + uint8_t InitParam4[10] = {0x01, 0xAA, 0x01, 0xAF, 0x01, + 0xAF, 0x10, 0xEA, 0x1C, 0xEA}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 10, 0xB4, + InitParam4) != HAL_OK) { + ErrorNumber++; + } + + /* SETVCOM */ + uint8_t InitParam5[4] = {00, 00, 00, 0xC0}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 4, 0xC7, + InitParam5) != HAL_OK) { + ErrorNumber++; + } + + /* Set Panel Related Registers */ + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xCC, + 0x02) != HAL_OK) { + ErrorNumber++; + } + + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xD2, + 0x77) != HAL_OK) { + ErrorNumber++; + } + + uint8_t InitParam6[37] = {0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x32, + 0x10, 0x01, 0x00, 0x01, 0x03, 0x72, 0x03, 0x72, + 0x00, 0x08, 0x00, 0x08, 0x33, 0x33, 0x05, 0x05, + 0x37, 0x05, 0x05, 0x37, 0x0A, 0x00, 0x00, 0x00, + 0x0A, 0x00, 0x01, 0x00, 0x0E}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 37, 0xD3, + InitParam6) != HAL_OK) { + ErrorNumber++; + } + + uint8_t InitParam7[34] = { + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06, + 0x23, 0x22, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 34, 0xD5, + InitParam7) != HAL_OK) { + ErrorNumber++; + } + + uint8_t InitParam8[32] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x19, 0x19, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18, + 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01, + 0x20, 0x21, 0x22, 0x23, 0x18, 0x18, 0x18, 0x18}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 35, 0xD6, + InitParam8) != HAL_OK) { + ErrorNumber++; + } + + /* SET GAMMA */ + uint8_t InitParam9[42] = { + 0x00, 0x16, 0x1B, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0D, 0x0F, + 0x18, 0x0E, 0x11, 0x12, 0x11, 0x14, 0x07, 0x12, 0x13, 0x18, 0x00, + 0x17, 0x1C, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0C, 0x0F, 0x18, + 0x0E, 0x11, 0x14, 0x11, 0x12, 0x07, 0x12, 0x14, 0x18}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xE0, + InitParam9) != HAL_OK) { + ErrorNumber++; + } + + uint8_t InitParam10[3] = {0x2C, 0x2C, 00}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB6, + InitParam10) != HAL_OK) { + ErrorNumber++; + } + + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, + 0x00) != HAL_OK) { + ErrorNumber++; + } + + uint8_t InitParam11[] = { + 0x01, 0x00, 0x07, 0x0F, 0x16, 0x1F, 0x27, 0x30, 0x38, 0x40, 0x47, + 0x4E, 0x56, 0x5D, 0x65, 0x6D, 0x74, 0x7D, 0x84, 0x8A, 0x90, 0x99, + 0xA1, 0xA9, 0xB0, 0xB6, 0xBD, 0xC4, 0xCD, 0xD4, 0xDD, 0xE5, 0xEC, + 0xF3, 0x36, 0x07, 0x1C, 0xC0, 0x1B, 0x01, 0xF1, 0x34, 0x00}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1, + InitParam11) != HAL_OK) { + ErrorNumber++; + } + + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, + 0x01) != HAL_OK) { + ErrorNumber++; + } + + uint8_t InitParam12[] = { + 0x00, 0x08, 0x0F, 0x16, 0x1F, 0x28, 0x31, 0x39, 0x41, 0x48, 0x51, + 0x59, 0x60, 0x68, 0x70, 0x78, 0x7F, 0x87, 0x8D, 0x94, 0x9C, 0xA3, + 0xAB, 0xB3, 0xB9, 0xC1, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xEE, 0xF5, + 0x3B, 0x1A, 0xB6, 0xA0, 0x07, 0x45, 0xC5, 0x37, 0x00}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1, + InitParam12) != HAL_OK) { + ErrorNumber++; + } + + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, + 0x02) != HAL_OK) { + ErrorNumber++; + } + + uint8_t InitParam13[42] = { + 0x00, 0x09, 0x0F, 0x18, 0x21, 0x2A, 0x34, 0x3C, 0x45, 0x4C, 0x56, + 0x5E, 0x66, 0x6E, 0x76, 0x7E, 0x87, 0x8E, 0x95, 0x9D, 0xA6, 0xAF, + 0xB7, 0xBD, 0xC5, 0xCE, 0xD5, 0xDF, 0xE7, 0xEE, 0xF4, 0xFA, 0xFF, + 0x0C, 0x31, 0x83, 0x3C, 0x5B, 0x56, 0x1E, 0x5A, 0xFF}; + if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1, + InitParam13) != HAL_OK) { + ErrorNumber++; + } + + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, + 0x00) != HAL_OK) { + ErrorNumber++; + } + + /* Exit Sleep Mode*/ + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x11, + 0x00) != HAL_OK) { + ErrorNumber++; + } + + HAL_Delay(120); + + /* Display On */ + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x29, + 0x00) != HAL_OK) { + ErrorNumber++; + } + + HAL_Delay(120); + + if (ErrorNumber != 0U) { + status = BSP_ERROR_PERIPH_FAILURE; + } + } + + return status; +} + +/** + * @brief De-Initialize LCD. + * @retval BSP status. + */ +static int32_t LCD_DeInit(void) { + int32_t status = BSP_ERROR_NONE; + uint32_t ErrorNumber = 0; + + /* Disable DSI wrapper */ + __HAL_DSI_WRAPPER_DISABLE(&hlcd_dsi); + + /* Set display off */ + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, + DSI_SET_DISPLAY_OFF, 0x00) != HAL_OK) { + ErrorNumber++; + } + + /* Wait before entering in sleep mode */ + HAL_Delay(2000); + + /* Put LCD in sleep mode */ + if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, + DSI_ENTER_SLEEP_MODE, 0x0) != HAL_OK) { + ErrorNumber++; + } + + HAL_Delay(120); + + /* De-initialize DSI */ + if (HAL_DSI_DeInit(&hlcd_dsi) != HAL_OK) { + ErrorNumber++; + } +#if (USE_HAL_DSI_REGISTER_CALLBACKS == 0) + DSI_MspDeInit(&hlcd_dsi); +#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 0) */ + + /* De-initialize LTDC */ + if (HAL_LTDC_DeInit(&hlcd_ltdc) != HAL_OK) { + ErrorNumber++; + } +#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 0) + LTDC_MspDeInit(&hlcd_ltdc); +#endif /* (USE_HAL_LTDC_REGISTER_CALLBACKS == 0) */ + + /* De-initialize GFXMMU */ + if (HAL_GFXMMU_DeInit(&hlcd_gfxmmu) != HAL_OK) { + ErrorNumber++; + } +#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) + GFXMMU_MspDeInit(&hlcd_gfxmmu); +#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */ + + if (ErrorNumber != 0U) { + status = BSP_ERROR_PERIPH_FAILURE; + } + + return status; +} + +/** + * @brief Initialize GFXMMU MSP. + * @param hgfxmmu GFXMMU handle + * @retval None + */ +static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(hgfxmmu); + + /* GFXMMU clock enable */ + __HAL_RCC_GFXMMU_CLK_ENABLE(); + + /* Enable GFXMMU interrupt */ + HAL_NVIC_SetPriority(GFXMMU_IRQn, BSP_LCD_GFXMMU_IT_PRIORITY, 0); + HAL_NVIC_EnableIRQ(GFXMMU_IRQn); +} + +/** + * @brief De-Initialize GFXMMU MSP. + * @param hgfxmmu GFXMMU handle + * @retval None + */ +static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(hgfxmmu); + + /* Disable GFXMMU interrupt */ + HAL_NVIC_DisableIRQ(GFXMMU_IRQn); + + /* GFXMMU clock disable */ + __HAL_RCC_GFXMMU_CLK_DISABLE(); +} + +/** + * @brief Initialize LTDC MSP. + * @param hltdc LTDC handle + * @retval None + */ +static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(hltdc); + + /* Enable LCD clock */ + __HAL_RCC_LTDC_CLK_ENABLE(); + + /* Enable LTDC interrupt */ + HAL_NVIC_SetPriority(LTDC_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); + HAL_NVIC_EnableIRQ(LTDC_IRQn); + + HAL_NVIC_SetPriority(LTDC_ER_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0); + HAL_NVIC_EnableIRQ(LTDC_ER_IRQn); +} + +/** + * @brief De-Initialize LTDC MSP. + * @param hltdc LTDC handle + * @retval None + */ +static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(hltdc); + + /* Disable LTDC interrupts */ + HAL_NVIC_DisableIRQ(LTDC_ER_IRQn); + HAL_NVIC_DisableIRQ(LTDC_IRQn); + + /* LTDC clock disable */ + __HAL_RCC_LTDC_CLK_DISABLE(); +} + +/** + * @brief Initialize DSI MSP. + * @param hdsi DSI handle + * @retval None + */ +static void DSI_MspInit(DSI_HandleTypeDef *hdsi) { + RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0}; + RCC_PeriphCLKInitTypeDef DSIPHYInitPeriph = {0}; + GPIO_InitTypeDef GPIO_InitStruct = {0}; + + UNUSED(hdsi); + + /* Enable GPIOI & GPIOD clocks */ + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOI_CLK_ENABLE(); + + /* Configure DSI Reset pin */ + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_PULLDOWN; + GPIO_InitStruct.Pin = GPIO_PIN_5; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + /* Configure LCD Backlight Pin */ + GPIO_InitStruct.Mode = GPIO_MODE_INPUT; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Pin = GPIO_PIN_6; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOI, &GPIO_InitStruct); + + /* Enable DSI clock */ + __HAL_RCC_DSI_CLK_ENABLE(); + + /** ################ Set DSI clock to D-PHY source clock ################## + * **/ + + /* Start and configurre PLL3 */ + /* HSE = 16MHZ */ + /* 16/(M=4) = 4MHz input (min) */ + /* 4*(N=125) = 500MHz VCO (almost max) */ + /* 500/(P=8) = 62.5 for DSI ie exactly the lane byte clock*/ + + PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI; + PLL3InitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; + PLL3InitPeriph.PLL3.PLL3M = 4; + PLL3InitPeriph.PLL3.PLL3N = 125; + PLL3InitPeriph.PLL3.PLL3P = 8; + PLL3InitPeriph.PLL3.PLL3Q = 8; + PLL3InitPeriph.PLL3.PLL3R = 24; + PLL3InitPeriph.PLL3.PLL3FRACN = 0; + PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1; + PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP; + PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; + (void)HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph); + + __HAL_RCC_DSI_CLK_ENABLE(); + + /* Switch to D-PHY source clock */ + /* Enable the DSI host */ + hlcd_dsi.Instance = DSI; + + __HAL_DSI_ENABLE(&hlcd_dsi); + + /* Enable the DSI PLL */ + __HAL_DSI_PLL_ENABLE(&hlcd_dsi); + + HAL_Delay(1); + + /* Enable the clock lane and the digital section of the D-PHY */ + hlcd_dsi.Instance->PCTLR |= (DSI_PCTLR_CKE | DSI_PCTLR_DEN); + + /* Set the TX escape clock division factor */ + hlcd_dsi.Instance->CCR = 4; + + HAL_Delay(1); + + /* Config DSI Clock to DSI PHY */ + DSIPHYInitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI; + DSIPHYInitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_DSIPHY; + + (void)HAL_RCCEx_PeriphCLKConfig(&DSIPHYInitPeriph); + + /* Reset */ + HAL_Delay(11); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_SET); + HAL_Delay(150); + + /* Reset the TX escape clock division factor */ + hlcd_dsi.Instance->CCR &= ~DSI_CCR_TXECKDIV; + + /* Disable the DSI PLL */ + __HAL_DSI_PLL_DISABLE(&hlcd_dsi); + + /* Disable the DSI host */ + __HAL_DSI_DISABLE(&hlcd_dsi); + + /** ######################################################################### + * **/ + + /* Enable DSI NVIC interrupt */ + /* Default is lowest priority level */ + HAL_NVIC_SetPriority(DSI_IRQn, 0x0FUL, 0); + HAL_NVIC_EnableIRQ(DSI_IRQn); +} + +/** + * @brief De-Initialize DSI MSP. + * @param hdsi DSI handle + * @retval None + */ +static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi) { + RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0}; + + UNUSED(hdsi); + + /* Switch to PLL3 before Disable */ + PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI; + PLL3InitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; + PLL3InitPeriph.PLL3.PLL3M = 4; + PLL3InitPeriph.PLL3.PLL3N = 125; + PLL3InitPeriph.PLL3.PLL3P = 8; + PLL3InitPeriph.PLL3.PLL3Q = 8; + PLL3InitPeriph.PLL3.PLL3R = 24; + PLL3InitPeriph.PLL3.PLL3FRACN = 0; + PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1; + PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP; + PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; + (void)HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph); + + /* DSI clock disable */ + __HAL_RCC_DSI_CLK_DISABLE(); + + /** @brief Toggle Sw reset of DSI IP */ + __HAL_RCC_DSI_FORCE_RESET(); + __HAL_RCC_DSI_RELEASE_RESET(); + + /* Disable DSI interrupts */ + HAL_NVIC_DisableIRQ(DSI_IRQn); +} + +void display_pixeldata(uint16_t c) { + uint32_t address = 0; + + if (act_frame_buffer == 0) { + address = GFXMMU_VIRTUAL_BUFFER1_BASE_S; + } else { + address = GFXMMU_VIRTUAL_BUFFER0_BASE_S; + } + + /* Get the rectangle start address */ + address = + (address + (4 * ((cursor_y + 120) * PIXEL_PER_LINE + (cursor_x + 120)))); + + *(__IO uint32_t *)(address) = rgb565_to_rgb888(c) | 0xFF000000; + + cursor_x++; + if (cursor_x > window_x1) { + cursor_x = window_x0; + cursor_y++; + } + if (cursor_y > window_y1) { + cursor_y = window_y0; + } +} + +// this is just for compatibility with DMA2D using algorithms +uint8_t *const DISPLAY_DATA_ADDRESS = 0; + +void display_reset_state() {} + +void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + window_x0 = x0; + window_y0 = y0; + window_x1 = x1; + window_y1 = y1; + cursor_x = x0; + cursor_y = y0; +} + +uint8_t *display_get_wr_addr(void) { + uint32_t address = 0; + + if (act_frame_buffer == 0) { + address = GFXMMU_VIRTUAL_BUFFER1_BASE_S; + } else { + address = GFXMMU_VIRTUAL_BUFFER0_BASE_S; + } + + /* Get the rectangle start address */ + address = + (address + (4 * ((cursor_y + 120) * PIXEL_PER_LINE + (cursor_x + 120)))); + + return (uint8_t *)address; +} + +uint32_t *display_get_fb_addr(void) { + uint32_t address = 0; + + if (act_frame_buffer == 0) { + address = GFXMMU_VIRTUAL_BUFFER1_BASE_S; + } else { + address = GFXMMU_VIRTUAL_BUFFER0_BASE_S; + } + + return (uint32_t *)address; +} + +void display_efficient_clear(void) { + if (act_frame_buffer == 0) { + memset(PhysFrameBuffer1, 0x00, sizeof(PhysFrameBuffer1)); + } else { + memset(PhysFrameBuffer0, 0x00, sizeof(PhysFrameBuffer0)); + } +} + +uint16_t display_get_window_width(void) { return window_x1 - window_x0 + 1; } + +uint16_t display_get_window_height(void) { return window_y1 - window_y0 + 1; } + +void display_shift_window(uint16_t pixels) { + uint16_t w = display_get_window_width(); + uint16_t h = display_get_window_height(); + + uint16_t line_rem = w - (cursor_x - window_x0); + + if (pixels < line_rem) { + cursor_x += pixels; + return; + } + + // start of next line + pixels = pixels - line_rem; + cursor_x = window_x0; + cursor_y++; + + // add the rest of pixels + cursor_y = window_y0 + (((cursor_y - window_y0) + (pixels / w)) % h); + cursor_x += pixels % w; +} + +uint16_t display_get_window_offset(void) { + return PIXEL_PER_LINE - display_get_window_width(); +} + +int display_orientation(int degrees) { return degrees; } + +int display_get_orientation(void) { return 0; } +int display_backlight(int val) { return val; } + +void display_init(void) { + RCC_PeriphCLKInitTypeDef PeriphClkInit = {0}; + + /** Initializes the common periph clock + */ + PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_DSI; + PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3; + PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3; + PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE; + PeriphClkInit.PLL3.PLL3M = 4; + PeriphClkInit.PLL3.PLL3N = 125; + PeriphClkInit.PLL3.PLL3P = 8; + PeriphClkInit.PLL3.PLL3Q = 2; + PeriphClkInit.PLL3.PLL3R = 24; + PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0; + PeriphClkInit.PLL3.PLL3FRACN = 0; + PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP | RCC_PLL3_DIVR; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit); + + memset(PhysFrameBuffer0, 0x00, sizeof(PhysFrameBuffer0)); + memset(PhysFrameBuffer1, 0x00, sizeof(PhysFrameBuffer1)); + memcpy(gfxmmu_lut, gfxmmu_lut_config_argb8888, + sizeof(gfxmmu_lut_config_argb8888)); + + BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT); + + BSP_LCD_SetBrightness(0, 100); + BSP_LCD_SetActiveLayer(0, 0); + BSP_LCD_DisplayOn(0); +} +void display_reinit(void) { + memcpy(gfxmmu_lut, gfxmmu_lut_config_argb8888, + sizeof(gfxmmu_lut_config_argb8888)); + + /* Switch to D-PHY source clock */ + /* Enable the DSI host */ + hlcd_dsi.Instance = DSI; + MX_GFXMMU_Reinit(&hlcd_gfxmmu); + MX_DSI_Reinit(&hlcd_dsi); + MX_LTDC_Reinit(&hlcd_ltdc); + + if (act_frame_buffer == 0) { + MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); + } else { + MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); + } +} +void display_sync(void) {} + +void display_refresh(void) { + if (act_frame_buffer == 0) { + act_frame_buffer = 1; + MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); + memcpy(PhysFrameBuffer0, PhysFrameBuffer1, sizeof(PhysFrameBuffer1)); + } else { + act_frame_buffer = 0; + MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); + memcpy(PhysFrameBuffer1, PhysFrameBuffer0, sizeof(PhysFrameBuffer1)); + } +} + +const char *display_save(const char *prefix) { return NULL; } + +void display_clear_save(void) {} + +void display_pixeldata_dirty(void) {} diff --git a/core/embed/trezorhal/stm32u5/displays/dsi.h b/core/embed/trezorhal/stm32u5/displays/dsi.h new file mode 100644 index 00000000000..a717e4bb715 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/dsi.h @@ -0,0 +1,30 @@ +#ifndef DSI_H_ +#define DSI_H_ + +#include STM32_HAL_H + +#define MAX_DISPLAY_RESX 240 +#define MAX_DISPLAY_RESY 240 +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888 +#define DISPLAY_FRAMEBUFFER_WIDTH 768 +#define DISPLAY_FRAMEBUFFER_HEIGHT 480 +#define DISPLAY_FRAMEBUFFER_OFFSET_X 120 +#define DISPLAY_FRAMEBUFFER_OFFSET_Y 120 +#define TREZOR_FONT_BPP 4 + +#define DISPLAY_EFFICIENT_CLEAR 1 + +extern uint8_t* const DISPLAY_DATA_ADDRESS; + +uint32_t rgb565_to_rgb888(uint16_t color); + +static inline void display_pixel(uint8_t* fb, int16_t x, int16_t y, + uint16_t color) { + uint32_t p = 4 * ((y + 120) * DISPLAY_FRAMEBUFFER_WIDTH + (x + 120)); + uint32_t c = rgb565_to_rgb888(color); + *((uint32_t*)(fb + p)) = c; +} + +#endif diff --git a/core/embed/trezorhal/stm32u5/displays/gfxmmu_lut.h b/core/embed/trezorhal/stm32u5/displays/gfxmmu_lut.h new file mode 100644 index 00000000000..7360378e8c4 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/gfxmmu_lut.h @@ -0,0 +1,1006 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * File Name : gfxmmu_lut.h + * Description : header file for GFX MMU Configuration Table + ****************************************************************************** + * @attention + * + * Copyright (c) 2022 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __gfxmmu_lut_H +#define __gfxmmu_lut_H +#ifdef __cplusplus +extern "C" { +#endif +// GFX MMU Configuration Table + +#define GFXMMU_FB_SIZE 733936 +#define GFXMMU_LUT_FIRST 0 +#define GFXMMU_LUT_LAST 479 +#define GFXMMU_LUT_SIZE 480 + +uint32_t gfxmmu_lut_config_argb8888[2 * GFXMMU_LUT_SIZE] = { + 0x00413601, // GFXMMU_LUT0L + 0x003FFCA0, // GFXMMU_LUT0H + 0x00433401, // GFXMMU_LUT1L + 0x003FFD80, // GFXMMU_LUT1H + 0x00453201, // GFXMMU_LUT2L + 0x003FFEA0, // GFXMMU_LUT2H + 0x00463101, // GFXMMU_LUT3L + 0x003FFFF0, // GFXMMU_LUT3H + 0x00482F01, // GFXMMU_LUT4L + 0x00000170, // GFXMMU_LUT4H + 0x00492E01, // GFXMMU_LUT5L + 0x00000320, // GFXMMU_LUT5H + 0x004A2D01, // GFXMMU_LUT6L + 0x000004F0, // GFXMMU_LUT6H + 0x004B2C01, // GFXMMU_LUT7L + 0x000006E0, // GFXMMU_LUT7H + 0x004C2B01, // GFXMMU_LUT8L + 0x000008F0, // GFXMMU_LUT8H + 0x004D2A01, // GFXMMU_LUT9L + 0x00000B20, // GFXMMU_LUT9H + 0x004D2A01, // GFXMMU_LUT10L + 0x00000D60, // GFXMMU_LUT10H + 0x004E2901, // GFXMMU_LUT11L + 0x00000FB0, // GFXMMU_LUT11H + 0x004F2801, // GFXMMU_LUT12L + 0x00001220, // GFXMMU_LUT12H + 0x00502701, // GFXMMU_LUT13L + 0x000014B0, // GFXMMU_LUT13H + 0x00502701, // GFXMMU_LUT14L + 0x00001750, // GFXMMU_LUT14H + 0x00512601, // GFXMMU_LUT15L + 0x00001A00, // GFXMMU_LUT15H + 0x00522501, // GFXMMU_LUT16L + 0x00001CD0, // GFXMMU_LUT16H + 0x00522501, // GFXMMU_LUT17L + 0x00001FB0, // GFXMMU_LUT17H + 0x00532401, // GFXMMU_LUT18L + 0x000022A0, // GFXMMU_LUT18H + 0x00532401, // GFXMMU_LUT19L + 0x000025A0, // GFXMMU_LUT19H + 0x00542301, // GFXMMU_LUT20L + 0x000028B0, // GFXMMU_LUT20H + 0x00552201, // GFXMMU_LUT21L + 0x00002BE0, // GFXMMU_LUT21H + 0x00552201, // GFXMMU_LUT22L + 0x00002F20, // GFXMMU_LUT22H + 0x00562101, // GFXMMU_LUT23L + 0x00003270, // GFXMMU_LUT23H + 0x00562101, // GFXMMU_LUT24L + 0x000035D0, // GFXMMU_LUT24H + 0x00572001, // GFXMMU_LUT25L + 0x00003940, // GFXMMU_LUT25H + 0x00572001, // GFXMMU_LUT26L + 0x00003CC0, // GFXMMU_LUT26H + 0x00581F01, // GFXMMU_LUT27L + 0x00004050, // GFXMMU_LUT27H + 0x00581F01, // GFXMMU_LUT28L + 0x000043F0, // GFXMMU_LUT28H + 0x00591E01, // GFXMMU_LUT29L + 0x000047A0, // GFXMMU_LUT29H + 0x00591E01, // GFXMMU_LUT30L + 0x00004B60, // GFXMMU_LUT30H + 0x00591E01, // GFXMMU_LUT31L + 0x00004F20, // GFXMMU_LUT31H + 0x005A1D01, // GFXMMU_LUT32L + 0x000052F0, // GFXMMU_LUT32H + 0x005A1D01, // GFXMMU_LUT33L + 0x000056D0, // GFXMMU_LUT33H + 0x005B1C01, // GFXMMU_LUT34L + 0x00005AC0, // GFXMMU_LUT34H + 0x005B1C01, // GFXMMU_LUT35L + 0x00005EC0, // GFXMMU_LUT35H + 0x005C1B01, // GFXMMU_LUT36L + 0x000062D0, // GFXMMU_LUT36H + 0x005C1B01, // GFXMMU_LUT37L + 0x000066F0, // GFXMMU_LUT37H + 0x005C1B01, // GFXMMU_LUT38L + 0x00006B10, // GFXMMU_LUT38H + 0x005D1A01, // GFXMMU_LUT39L + 0x00006F40, // GFXMMU_LUT39H + 0x005D1A01, // GFXMMU_LUT40L + 0x00007380, // GFXMMU_LUT40H + 0x005D1A01, // GFXMMU_LUT41L + 0x000077C0, // GFXMMU_LUT41H + 0x005E1901, // GFXMMU_LUT42L + 0x00007C10, // GFXMMU_LUT42H + 0x005E1901, // GFXMMU_LUT43L + 0x00008070, // GFXMMU_LUT43H + 0x005E1901, // GFXMMU_LUT44L + 0x000084D0, // GFXMMU_LUT44H + 0x005F1801, // GFXMMU_LUT45L + 0x00008940, // GFXMMU_LUT45H + 0x005F1801, // GFXMMU_LUT46L + 0x00008DC0, // GFXMMU_LUT46H + 0x00601801, // GFXMMU_LUT47L + 0x00009240, // GFXMMU_LUT47H + 0x00601701, // GFXMMU_LUT48L + 0x000096E0, // GFXMMU_LUT48H + 0x00601701, // GFXMMU_LUT49L + 0x00009B80, // GFXMMU_LUT49H + 0x00601701, // GFXMMU_LUT50L + 0x0000A020, // GFXMMU_LUT50H + 0x00611601, // GFXMMU_LUT51L + 0x0000A4D0, // GFXMMU_LUT51H + 0x00611601, // GFXMMU_LUT52L + 0x0000A990, // GFXMMU_LUT52H + 0x00611601, // GFXMMU_LUT53L + 0x0000AE50, // GFXMMU_LUT53H + 0x00621501, // GFXMMU_LUT54L + 0x0000B320, // GFXMMU_LUT54H + 0x00621501, // GFXMMU_LUT55L + 0x0000B800, // GFXMMU_LUT55H + 0x00621501, // GFXMMU_LUT56L + 0x0000BCE0, // GFXMMU_LUT56H + 0x00631401, // GFXMMU_LUT57L + 0x0000C1D0, // GFXMMU_LUT57H + 0x00631401, // GFXMMU_LUT58L + 0x0000C6D0, // GFXMMU_LUT58H + 0x00631401, // GFXMMU_LUT59L + 0x0000CBD0, // GFXMMU_LUT59H + 0x00631401, // GFXMMU_LUT60L + 0x0000D0D0, // GFXMMU_LUT60H + 0x00641301, // GFXMMU_LUT61L + 0x0000D5E0, // GFXMMU_LUT61H + 0x00641301, // GFXMMU_LUT62L + 0x0000DB00, // GFXMMU_LUT62H + 0x00641301, // GFXMMU_LUT63L + 0x0000E020, // GFXMMU_LUT63H + 0x00651201, // GFXMMU_LUT64L + 0x0000E550, // GFXMMU_LUT64H + 0x00651201, // GFXMMU_LUT65L + 0x0000EA90, // GFXMMU_LUT65H + 0x00651201, // GFXMMU_LUT66L + 0x0000EFD0, // GFXMMU_LUT66H + 0x00651201, // GFXMMU_LUT67L + 0x0000F510, // GFXMMU_LUT67H + 0x00661101, // GFXMMU_LUT68L + 0x0000FA60, // GFXMMU_LUT68H + 0x00661101, // GFXMMU_LUT69L + 0x0000FFC0, // GFXMMU_LUT69H + 0x00661101, // GFXMMU_LUT70L + 0x00010520, // GFXMMU_LUT70H + 0x00661101, // GFXMMU_LUT71L + 0x00010A80, // GFXMMU_LUT71H + 0x00671001, // GFXMMU_LUT72L + 0x00010FF0, // GFXMMU_LUT72H + 0x00671001, // GFXMMU_LUT73L + 0x00011570, // GFXMMU_LUT73H + 0x00671001, // GFXMMU_LUT74L + 0x00011AF0, // GFXMMU_LUT74H + 0x00671001, // GFXMMU_LUT75L + 0x00012070, // GFXMMU_LUT75H + 0x00680F01, // GFXMMU_LUT76L + 0x00012600, // GFXMMU_LUT76H + 0x00680F01, // GFXMMU_LUT77L + 0x00012BA0, // GFXMMU_LUT77H + 0x00680F01, // GFXMMU_LUT78L + 0x00013140, // GFXMMU_LUT78H + 0x00680F01, // GFXMMU_LUT79L + 0x000136E0, // GFXMMU_LUT79H + 0x00680F01, // GFXMMU_LUT80L + 0x00013C80, // GFXMMU_LUT80H + 0x00690E01, // GFXMMU_LUT81L + 0x00014230, // GFXMMU_LUT81H + 0x00690E01, // GFXMMU_LUT82L + 0x000147F0, // GFXMMU_LUT82H + 0x00690E01, // GFXMMU_LUT83L + 0x00014DB0, // GFXMMU_LUT83H + 0x00690E01, // GFXMMU_LUT84L + 0x00015370, // GFXMMU_LUT84H + 0x006A0D01, // GFXMMU_LUT85L + 0x00015940, // GFXMMU_LUT85H + 0x006A0D01, // GFXMMU_LUT86L + 0x00015F20, // GFXMMU_LUT86H + 0x006A0D01, // GFXMMU_LUT87L + 0x00016500, // GFXMMU_LUT87H + 0x006A0D01, // GFXMMU_LUT88L + 0x00016AE0, // GFXMMU_LUT88H + 0x006A0D01, // GFXMMU_LUT89L + 0x000170C0, // GFXMMU_LUT89H + 0x006B0C01, // GFXMMU_LUT90L + 0x000176B0, // GFXMMU_LUT90H + 0x006B0C01, // GFXMMU_LUT91L + 0x00017CB0, // GFXMMU_LUT91H + 0x006B0C01, // GFXMMU_LUT92L + 0x000182B0, // GFXMMU_LUT92H + 0x006B0C01, // GFXMMU_LUT93L + 0x000188B0, // GFXMMU_LUT93H + 0x006B0C01, // GFXMMU_LUT94L + 0x00018EB0, // GFXMMU_LUT94H + 0x006C0C01, // GFXMMU_LUT95L + 0x000194B0, // GFXMMU_LUT95H + 0x006C0B01, // GFXMMU_LUT96L + 0x00019AD0, // GFXMMU_LUT96H + 0x006C0B01, // GFXMMU_LUT97L + 0x0001A0F0, // GFXMMU_LUT97H + 0x006C0B01, // GFXMMU_LUT98L + 0x0001A710, // GFXMMU_LUT98H + 0x006C0B01, // GFXMMU_LUT99L + 0x0001AD30, // GFXMMU_LUT99H + 0x006C0B01, // GFXMMU_LUT100L + 0x0001B350, // GFXMMU_LUT100H + 0x006D0A01, // GFXMMU_LUT101L + 0x0001B980, // GFXMMU_LUT101H + 0x006D0A01, // GFXMMU_LUT102L + 0x0001BFC0, // GFXMMU_LUT102H + 0x006D0A01, // GFXMMU_LUT103L + 0x0001C600, // GFXMMU_LUT103H + 0x006D0A01, // GFXMMU_LUT104L + 0x0001CC40, // GFXMMU_LUT104H + 0x006D0A01, // GFXMMU_LUT105L + 0x0001D280, // GFXMMU_LUT105H + 0x006D0A01, // GFXMMU_LUT106L + 0x0001D8C0, // GFXMMU_LUT106H + 0x006E0901, // GFXMMU_LUT107L + 0x0001DF10, // GFXMMU_LUT107H + 0x006E0901, // GFXMMU_LUT108L + 0x0001E570, // GFXMMU_LUT108H + 0x006E0901, // GFXMMU_LUT109L + 0x0001EBD0, // GFXMMU_LUT109H + 0x006E0901, // GFXMMU_LUT110L + 0x0001F230, // GFXMMU_LUT110H + 0x006E0901, // GFXMMU_LUT111L + 0x0001F890, // GFXMMU_LUT111H + 0x006E0901, // GFXMMU_LUT112L + 0x0001FEF0, // GFXMMU_LUT112H + 0x006F0801, // GFXMMU_LUT113L + 0x00020560, // GFXMMU_LUT113H + 0x006F0801, // GFXMMU_LUT114L + 0x00020BE0, // GFXMMU_LUT114H + 0x006F0801, // GFXMMU_LUT115L + 0x00021260, // GFXMMU_LUT115H + 0x006F0801, // GFXMMU_LUT116L + 0x000218E0, // GFXMMU_LUT116H + 0x006F0801, // GFXMMU_LUT117L + 0x00021F60, // GFXMMU_LUT117H + 0x006F0801, // GFXMMU_LUT118L + 0x000225E0, // GFXMMU_LUT118H + 0x006F0801, // GFXMMU_LUT119L + 0x00022C60, // GFXMMU_LUT119H + 0x00700701, // GFXMMU_LUT120L + 0x000232F0, // GFXMMU_LUT120H + 0x00700701, // GFXMMU_LUT121L + 0x00023990, // GFXMMU_LUT121H + 0x00700701, // GFXMMU_LUT122L + 0x00024030, // GFXMMU_LUT122H + 0x00700701, // GFXMMU_LUT123L + 0x000246D0, // GFXMMU_LUT123H + 0x00700701, // GFXMMU_LUT124L + 0x00024D70, // GFXMMU_LUT124H + 0x00700701, // GFXMMU_LUT125L + 0x00025410, // GFXMMU_LUT125H + 0x00700701, // GFXMMU_LUT126L + 0x00025AB0, // GFXMMU_LUT126H + 0x00710601, // GFXMMU_LUT127L + 0x00026160, // GFXMMU_LUT127H + 0x00710601, // GFXMMU_LUT128L + 0x00026820, // GFXMMU_LUT128H + 0x00710601, // GFXMMU_LUT129L + 0x00026EE0, // GFXMMU_LUT129H + 0x00710601, // GFXMMU_LUT130L + 0x000275A0, // GFXMMU_LUT130H + 0x00710601, // GFXMMU_LUT131L + 0x00027C60, // GFXMMU_LUT131H + 0x00710601, // GFXMMU_LUT132L + 0x00028320, // GFXMMU_LUT132H + 0x00710601, // GFXMMU_LUT133L + 0x000289E0, // GFXMMU_LUT133H + 0x00710601, // GFXMMU_LUT134L + 0x000290A0, // GFXMMU_LUT134H + 0x00720501, // GFXMMU_LUT135L + 0x00029770, // GFXMMU_LUT135H + 0x00720501, // GFXMMU_LUT136L + 0x00029E50, // GFXMMU_LUT136H + 0x00720501, // GFXMMU_LUT137L + 0x0002A530, // GFXMMU_LUT137H + 0x00720501, // GFXMMU_LUT138L + 0x0002AC10, // GFXMMU_LUT138H + 0x00720501, // GFXMMU_LUT139L + 0x0002B2F0, // GFXMMU_LUT139H + 0x00720501, // GFXMMU_LUT140L + 0x0002B9D0, // GFXMMU_LUT140H + 0x00720501, // GFXMMU_LUT141L + 0x0002C0B0, // GFXMMU_LUT141H + 0x00720501, // GFXMMU_LUT142L + 0x0002C790, // GFXMMU_LUT142H + 0x00720501, // GFXMMU_LUT143L + 0x0002CE70, // GFXMMU_LUT143H + 0x00730401, // GFXMMU_LUT144L + 0x0002D560, // GFXMMU_LUT144H + 0x00730401, // GFXMMU_LUT145L + 0x0002DC60, // GFXMMU_LUT145H + 0x00730401, // GFXMMU_LUT146L + 0x0002E360, // GFXMMU_LUT146H + 0x00730401, // GFXMMU_LUT147L + 0x0002EA60, // GFXMMU_LUT147H + 0x00730401, // GFXMMU_LUT148L + 0x0002F160, // GFXMMU_LUT148H + 0x00730401, // GFXMMU_LUT149L + 0x0002F860, // GFXMMU_LUT149H + 0x00730401, // GFXMMU_LUT150L + 0x0002FF60, // GFXMMU_LUT150H + 0x00730401, // GFXMMU_LUT151L + 0x00030660, // GFXMMU_LUT151H + 0x00730401, // GFXMMU_LUT152L + 0x00030D60, // GFXMMU_LUT152H + 0x00740301, // GFXMMU_LUT153L + 0x00031470, // GFXMMU_LUT153H + 0x00740301, // GFXMMU_LUT154L + 0x00031B90, // GFXMMU_LUT154H + 0x00740301, // GFXMMU_LUT155L + 0x000322B0, // GFXMMU_LUT155H + 0x00740301, // GFXMMU_LUT156L + 0x000329D0, // GFXMMU_LUT156H + 0x00740301, // GFXMMU_LUT157L + 0x000330F0, // GFXMMU_LUT157H + 0x00740301, // GFXMMU_LUT158L + 0x00033810, // GFXMMU_LUT158H + 0x00740301, // GFXMMU_LUT159L + 0x00033F30, // GFXMMU_LUT159H + 0x00740301, // GFXMMU_LUT160L + 0x00034650, // GFXMMU_LUT160H + 0x00740301, // GFXMMU_LUT161L + 0x00034D70, // GFXMMU_LUT161H + 0x00740301, // GFXMMU_LUT162L + 0x00035490, // GFXMMU_LUT162H + 0x00740301, // GFXMMU_LUT163L + 0x00035BB0, // GFXMMU_LUT163H + 0x00740301, // GFXMMU_LUT164L + 0x000362D0, // GFXMMU_LUT164H + 0x00750201, // GFXMMU_LUT165L + 0x00036A00, // GFXMMU_LUT165H + 0x00750201, // GFXMMU_LUT166L + 0x00037140, // GFXMMU_LUT166H + 0x00750201, // GFXMMU_LUT167L + 0x00037880, // GFXMMU_LUT167H + 0x00750201, // GFXMMU_LUT168L + 0x00037FC0, // GFXMMU_LUT168H + 0x00750201, // GFXMMU_LUT169L + 0x00038700, // GFXMMU_LUT169H + 0x00750201, // GFXMMU_LUT170L + 0x00038E40, // GFXMMU_LUT170H + 0x00750201, // GFXMMU_LUT171L + 0x00039580, // GFXMMU_LUT171H + 0x00750201, // GFXMMU_LUT172L + 0x00039CC0, // GFXMMU_LUT172H + 0x00750201, // GFXMMU_LUT173L + 0x0003A400, // GFXMMU_LUT173H + 0x00750201, // GFXMMU_LUT174L + 0x0003AB40, // GFXMMU_LUT174H + 0x00750201, // GFXMMU_LUT175L + 0x0003B280, // GFXMMU_LUT175H + 0x00750201, // GFXMMU_LUT176L + 0x0003B9C0, // GFXMMU_LUT176H + 0x00750201, // GFXMMU_LUT177L + 0x0003C100, // GFXMMU_LUT177H + 0x00760101, // GFXMMU_LUT178L + 0x0003C850, // GFXMMU_LUT178H + 0x00760101, // GFXMMU_LUT179L + 0x0003CFB0, // GFXMMU_LUT179H + 0x00760101, // GFXMMU_LUT180L + 0x0003D710, // GFXMMU_LUT180H + 0x00760101, // GFXMMU_LUT181L + 0x0003DE70, // GFXMMU_LUT181H + 0x00760101, // GFXMMU_LUT182L + 0x0003E5D0, // GFXMMU_LUT182H + 0x00760101, // GFXMMU_LUT183L + 0x0003ED30, // GFXMMU_LUT183H + 0x00760101, // GFXMMU_LUT184L + 0x0003F490, // GFXMMU_LUT184H + 0x00760101, // GFXMMU_LUT185L + 0x0003FBF0, // GFXMMU_LUT185H + 0x00760101, // GFXMMU_LUT186L + 0x00040350, // GFXMMU_LUT186H + 0x00760101, // GFXMMU_LUT187L + 0x00040AB0, // GFXMMU_LUT187H + 0x00760101, // GFXMMU_LUT188L + 0x00041210, // GFXMMU_LUT188H + 0x00760101, // GFXMMU_LUT189L + 0x00041970, // GFXMMU_LUT189H + 0x00760101, // GFXMMU_LUT190L + 0x000420D0, // GFXMMU_LUT190H + 0x00760101, // GFXMMU_LUT191L + 0x00042830, // GFXMMU_LUT191H + 0x00760101, // GFXMMU_LUT192L + 0x00042F90, // GFXMMU_LUT192H + 0x00760101, // GFXMMU_LUT193L + 0x000436F0, // GFXMMU_LUT193H + 0x00760101, // GFXMMU_LUT194L + 0x00043E50, // GFXMMU_LUT194H + 0x00760101, // GFXMMU_LUT195L + 0x000445B0, // GFXMMU_LUT195H + 0x00770001, // GFXMMU_LUT196L + 0x00044D20, // GFXMMU_LUT196H + 0x00770001, // GFXMMU_LUT197L + 0x000454A0, // GFXMMU_LUT197H + 0x00770001, // GFXMMU_LUT198L + 0x00045C20, // GFXMMU_LUT198H + 0x00770001, // GFXMMU_LUT199L + 0x000463A0, // GFXMMU_LUT199H + 0x00770001, // GFXMMU_LUT200L + 0x00046B20, // GFXMMU_LUT200H + 0x00770001, // GFXMMU_LUT201L + 0x000472A0, // GFXMMU_LUT201H + 0x00770001, // GFXMMU_LUT202L + 0x00047A20, // GFXMMU_LUT202H + 0x00770001, // GFXMMU_LUT203L + 0x000481A0, // GFXMMU_LUT203H + 0x00770001, // GFXMMU_LUT204L + 0x00048920, // GFXMMU_LUT204H + 0x00770001, // GFXMMU_LUT205L + 0x000490A0, // GFXMMU_LUT205H + 0x00770001, // GFXMMU_LUT206L + 0x00049820, // GFXMMU_LUT206H + 0x00770001, // GFXMMU_LUT207L + 0x00049FA0, // GFXMMU_LUT207H + 0x00770001, // GFXMMU_LUT208L + 0x0004A720, // GFXMMU_LUT208H + 0x00770001, // GFXMMU_LUT209L + 0x0004AEA0, // GFXMMU_LUT209H + 0x00770001, // GFXMMU_LUT210L + 0x0004B620, // GFXMMU_LUT210H + 0x00770001, // GFXMMU_LUT211L + 0x0004BDA0, // GFXMMU_LUT211H + 0x00770001, // GFXMMU_LUT212L + 0x0004C520, // GFXMMU_LUT212H + 0x00770001, // GFXMMU_LUT213L + 0x0004CCA0, // GFXMMU_LUT213H + 0x00770001, // GFXMMU_LUT214L + 0x0004D420, // GFXMMU_LUT214H + 0x00770001, // GFXMMU_LUT215L + 0x0004DBA0, // GFXMMU_LUT215H + 0x00770001, // GFXMMU_LUT216L + 0x0004E320, // GFXMMU_LUT216H + 0x00770001, // GFXMMU_LUT217L + 0x0004EAA0, // GFXMMU_LUT217H + 0x00770001, // GFXMMU_LUT218L + 0x0004F220, // GFXMMU_LUT218H + 0x00770001, // GFXMMU_LUT219L + 0x0004F9A0, // GFXMMU_LUT219H + 0x00770001, // GFXMMU_LUT220L + 0x00050120, // GFXMMU_LUT220H + 0x00770001, // GFXMMU_LUT221L + 0x000508A0, // GFXMMU_LUT221H + 0x00770001, // GFXMMU_LUT222L + 0x00051020, // GFXMMU_LUT222H + 0x00770001, // GFXMMU_LUT223L + 0x000517A0, // GFXMMU_LUT223H + 0x00770001, // GFXMMU_LUT224L + 0x00051F20, // GFXMMU_LUT224H + 0x00770001, // GFXMMU_LUT225L + 0x000526A0, // GFXMMU_LUT225H + 0x00770001, // GFXMMU_LUT226L + 0x00052E20, // GFXMMU_LUT226H + 0x00770001, // GFXMMU_LUT227L + 0x000535A0, // GFXMMU_LUT227H + 0x00770001, // GFXMMU_LUT228L + 0x00053D20, // GFXMMU_LUT228H + 0x00770001, // GFXMMU_LUT229L + 0x000544A0, // GFXMMU_LUT229H + 0x00770001, // GFXMMU_LUT230L + 0x00054C20, // GFXMMU_LUT230H + 0x00770001, // GFXMMU_LUT231L + 0x000553A0, // GFXMMU_LUT231H + 0x00770001, // GFXMMU_LUT232L + 0x00055B20, // GFXMMU_LUT232H + 0x00770001, // GFXMMU_LUT233L + 0x000562A0, // GFXMMU_LUT233H + 0x00770001, // GFXMMU_LUT234L + 0x00056A20, // GFXMMU_LUT234H + 0x00770001, // GFXMMU_LUT235L + 0x000571A0, // GFXMMU_LUT235H + 0x00770001, // GFXMMU_LUT236L + 0x00057920, // GFXMMU_LUT236H + 0x00770001, // GFXMMU_LUT237L + 0x000580A0, // GFXMMU_LUT237H + 0x00770001, // GFXMMU_LUT238L + 0x00058820, // GFXMMU_LUT238H + 0x00770001, // GFXMMU_LUT239L + 0x00058FA0, // GFXMMU_LUT239H + 0x00780001, // GFXMMU_LUT240L + 0x00059720, // GFXMMU_LUT240H + 0x00770001, // GFXMMU_LUT241L + 0x00059EB0, // GFXMMU_LUT241H + 0x00770001, // GFXMMU_LUT242L + 0x0005A630, // GFXMMU_LUT242H + 0x00770001, // GFXMMU_LUT243L + 0x0005ADB0, // GFXMMU_LUT243H + 0x00770001, // GFXMMU_LUT244L + 0x0005B530, // GFXMMU_LUT244H + 0x00770001, // GFXMMU_LUT245L + 0x0005BCB0, // GFXMMU_LUT245H + 0x00770001, // GFXMMU_LUT246L + 0x0005C430, // GFXMMU_LUT246H + 0x00770001, // GFXMMU_LUT247L + 0x0005CBB0, // GFXMMU_LUT247H + 0x00770001, // GFXMMU_LUT248L + 0x0005D330, // GFXMMU_LUT248H + 0x00770001, // GFXMMU_LUT249L + 0x0005DAB0, // GFXMMU_LUT249H + 0x00770001, // GFXMMU_LUT250L + 0x0005E230, // GFXMMU_LUT250H + 0x00770001, // GFXMMU_LUT251L + 0x0005E9B0, // GFXMMU_LUT251H + 0x00770001, // GFXMMU_LUT252L + 0x0005F130, // GFXMMU_LUT252H + 0x00770001, // GFXMMU_LUT253L + 0x0005F8B0, // GFXMMU_LUT253H + 0x00770001, // GFXMMU_LUT254L + 0x00060030, // GFXMMU_LUT254H + 0x00770001, // GFXMMU_LUT255L + 0x000607B0, // GFXMMU_LUT255H + 0x00770001, // GFXMMU_LUT256L + 0x00060F30, // GFXMMU_LUT256H + 0x00770001, // GFXMMU_LUT257L + 0x000616B0, // GFXMMU_LUT257H + 0x00770001, // GFXMMU_LUT258L + 0x00061E30, // GFXMMU_LUT258H + 0x00770001, // GFXMMU_LUT259L + 0x000625B0, // GFXMMU_LUT259H + 0x00770001, // GFXMMU_LUT260L + 0x00062D30, // GFXMMU_LUT260H + 0x00770001, // GFXMMU_LUT261L + 0x000634B0, // GFXMMU_LUT261H + 0x00770001, // GFXMMU_LUT262L + 0x00063C30, // GFXMMU_LUT262H + 0x00770001, // GFXMMU_LUT263L + 0x000643B0, // GFXMMU_LUT263H + 0x00770001, // GFXMMU_LUT264L + 0x00064B30, // GFXMMU_LUT264H + 0x00770001, // GFXMMU_LUT265L + 0x000652B0, // GFXMMU_LUT265H + 0x00770001, // GFXMMU_LUT266L + 0x00065A30, // GFXMMU_LUT266H + 0x00770001, // GFXMMU_LUT267L + 0x000661B0, // GFXMMU_LUT267H + 0x00770001, // GFXMMU_LUT268L + 0x00066930, // GFXMMU_LUT268H + 0x00770001, // GFXMMU_LUT269L + 0x000670B0, // GFXMMU_LUT269H + 0x00770001, // GFXMMU_LUT270L + 0x00067830, // GFXMMU_LUT270H + 0x00770001, // GFXMMU_LUT271L + 0x00067FB0, // GFXMMU_LUT271H + 0x00770001, // GFXMMU_LUT272L + 0x00068730, // GFXMMU_LUT272H + 0x00770001, // GFXMMU_LUT273L + 0x00068EB0, // GFXMMU_LUT273H + 0x00770001, // GFXMMU_LUT274L + 0x00069630, // GFXMMU_LUT274H + 0x00770001, // GFXMMU_LUT275L + 0x00069DB0, // GFXMMU_LUT275H + 0x00770001, // GFXMMU_LUT276L + 0x0006A530, // GFXMMU_LUT276H + 0x00770001, // GFXMMU_LUT277L + 0x0006ACB0, // GFXMMU_LUT277H + 0x00770001, // GFXMMU_LUT278L + 0x0006B430, // GFXMMU_LUT278H + 0x00770001, // GFXMMU_LUT279L + 0x0006BBB0, // GFXMMU_LUT279H + 0x00770001, // GFXMMU_LUT280L + 0x0006C330, // GFXMMU_LUT280H + 0x00770001, // GFXMMU_LUT281L + 0x0006CAB0, // GFXMMU_LUT281H + 0x00770001, // GFXMMU_LUT282L + 0x0006D230, // GFXMMU_LUT282H + 0x00770001, // GFXMMU_LUT283L + 0x0006D9B0, // GFXMMU_LUT283H + 0x00770001, // GFXMMU_LUT284L + 0x0006E130, // GFXMMU_LUT284H + 0x00760101, // GFXMMU_LUT285L + 0x0006E8A0, // GFXMMU_LUT285H + 0x00760101, // GFXMMU_LUT286L + 0x0006F000, // GFXMMU_LUT286H + 0x00760101, // GFXMMU_LUT287L + 0x0006F760, // GFXMMU_LUT287H + 0x00760101, // GFXMMU_LUT288L + 0x0006FEC0, // GFXMMU_LUT288H + 0x00760101, // GFXMMU_LUT289L + 0x00070620, // GFXMMU_LUT289H + 0x00760101, // GFXMMU_LUT290L + 0x00070D80, // GFXMMU_LUT290H + 0x00760101, // GFXMMU_LUT291L + 0x000714E0, // GFXMMU_LUT291H + 0x00760101, // GFXMMU_LUT292L + 0x00071C40, // GFXMMU_LUT292H + 0x00760101, // GFXMMU_LUT293L + 0x000723A0, // GFXMMU_LUT293H + 0x00760101, // GFXMMU_LUT294L + 0x00072B00, // GFXMMU_LUT294H + 0x00760101, // GFXMMU_LUT295L + 0x00073260, // GFXMMU_LUT295H + 0x00760101, // GFXMMU_LUT296L + 0x000739C0, // GFXMMU_LUT296H + 0x00760101, // GFXMMU_LUT297L + 0x00074120, // GFXMMU_LUT297H + 0x00760101, // GFXMMU_LUT298L + 0x00074880, // GFXMMU_LUT298H + 0x00760101, // GFXMMU_LUT299L + 0x00074FE0, // GFXMMU_LUT299H + 0x00760101, // GFXMMU_LUT300L + 0x00075740, // GFXMMU_LUT300H + 0x00760101, // GFXMMU_LUT301L + 0x00075EA0, // GFXMMU_LUT301H + 0x00760101, // GFXMMU_LUT302L + 0x00076600, // GFXMMU_LUT302H + 0x00750201, // GFXMMU_LUT303L + 0x00076D50, // GFXMMU_LUT303H + 0x00750201, // GFXMMU_LUT304L + 0x00077490, // GFXMMU_LUT304H + 0x00750201, // GFXMMU_LUT305L + 0x00077BD0, // GFXMMU_LUT305H + 0x00750201, // GFXMMU_LUT306L + 0x00078310, // GFXMMU_LUT306H + 0x00750201, // GFXMMU_LUT307L + 0x00078A50, // GFXMMU_LUT307H + 0x00750201, // GFXMMU_LUT308L + 0x00079190, // GFXMMU_LUT308H + 0x00750201, // GFXMMU_LUT309L + 0x000798D0, // GFXMMU_LUT309H + 0x00750201, // GFXMMU_LUT310L + 0x0007A010, // GFXMMU_LUT310H + 0x00750201, // GFXMMU_LUT311L + 0x0007A750, // GFXMMU_LUT311H + 0x00750201, // GFXMMU_LUT312L + 0x0007AE90, // GFXMMU_LUT312H + 0x00750201, // GFXMMU_LUT313L + 0x0007B5D0, // GFXMMU_LUT313H + 0x00750201, // GFXMMU_LUT314L + 0x0007BD10, // GFXMMU_LUT314H + 0x00750201, // GFXMMU_LUT315L + 0x0007C450, // GFXMMU_LUT315H + 0x00740301, // GFXMMU_LUT316L + 0x0007CB80, // GFXMMU_LUT316H + 0x00740301, // GFXMMU_LUT317L + 0x0007D2A0, // GFXMMU_LUT317H + 0x00740301, // GFXMMU_LUT318L + 0x0007D9C0, // GFXMMU_LUT318H + 0x00740301, // GFXMMU_LUT319L + 0x0007E0E0, // GFXMMU_LUT319H + 0x00740301, // GFXMMU_LUT320L + 0x0007E800, // GFXMMU_LUT320H + 0x00740301, // GFXMMU_LUT321L + 0x0007EF20, // GFXMMU_LUT321H + 0x00740301, // GFXMMU_LUT322L + 0x0007F640, // GFXMMU_LUT322H + 0x00740301, // GFXMMU_LUT323L + 0x0007FD60, // GFXMMU_LUT323H + 0x00740301, // GFXMMU_LUT324L + 0x00080480, // GFXMMU_LUT324H + 0x00740301, // GFXMMU_LUT325L + 0x00080BA0, // GFXMMU_LUT325H + 0x00740301, // GFXMMU_LUT326L + 0x000812C0, // GFXMMU_LUT326H + 0x00740301, // GFXMMU_LUT327L + 0x000819E0, // GFXMMU_LUT327H + 0x00730401, // GFXMMU_LUT328L + 0x000820F0, // GFXMMU_LUT328H + 0x00730401, // GFXMMU_LUT329L + 0x000827F0, // GFXMMU_LUT329H + 0x00730401, // GFXMMU_LUT330L + 0x00082EF0, // GFXMMU_LUT330H + 0x00730401, // GFXMMU_LUT331L + 0x000835F0, // GFXMMU_LUT331H + 0x00730401, // GFXMMU_LUT332L + 0x00083CF0, // GFXMMU_LUT332H + 0x00730401, // GFXMMU_LUT333L + 0x000843F0, // GFXMMU_LUT333H + 0x00730401, // GFXMMU_LUT334L + 0x00084AF0, // GFXMMU_LUT334H + 0x00730401, // GFXMMU_LUT335L + 0x000851F0, // GFXMMU_LUT335H + 0x00730401, // GFXMMU_LUT336L + 0x000858F0, // GFXMMU_LUT336H + 0x00730401, // GFXMMU_LUT337L + 0x00085FF0, // GFXMMU_LUT337H + 0x00720501, // GFXMMU_LUT338L + 0x000866E0, // GFXMMU_LUT338H + 0x00720501, // GFXMMU_LUT339L + 0x00086DC0, // GFXMMU_LUT339H + 0x00720501, // GFXMMU_LUT340L + 0x000874A0, // GFXMMU_LUT340H + 0x00720501, // GFXMMU_LUT341L + 0x00087B80, // GFXMMU_LUT341H + 0x00720501, // GFXMMU_LUT342L + 0x00088260, // GFXMMU_LUT342H + 0x00720501, // GFXMMU_LUT343L + 0x00088940, // GFXMMU_LUT343H + 0x00720501, // GFXMMU_LUT344L + 0x00089020, // GFXMMU_LUT344H + 0x00720501, // GFXMMU_LUT345L + 0x00089700, // GFXMMU_LUT345H + 0x00710601, // GFXMMU_LUT346L + 0x00089DD0, // GFXMMU_LUT346H + 0x00710601, // GFXMMU_LUT347L + 0x0008A490, // GFXMMU_LUT347H + 0x00710601, // GFXMMU_LUT348L + 0x0008AB50, // GFXMMU_LUT348H + 0x00710601, // GFXMMU_LUT349L + 0x0008B210, // GFXMMU_LUT349H + 0x00710601, // GFXMMU_LUT350L + 0x0008B8D0, // GFXMMU_LUT350H + 0x00710601, // GFXMMU_LUT351L + 0x0008BF90, // GFXMMU_LUT351H + 0x00710601, // GFXMMU_LUT352L + 0x0008C650, // GFXMMU_LUT352H + 0x00710601, // GFXMMU_LUT353L + 0x0008CD10, // GFXMMU_LUT353H + 0x00700701, // GFXMMU_LUT354L + 0x0008D3C0, // GFXMMU_LUT354H + 0x00700701, // GFXMMU_LUT355L + 0x0008DA60, // GFXMMU_LUT355H + 0x00700701, // GFXMMU_LUT356L + 0x0008E100, // GFXMMU_LUT356H + 0x00700701, // GFXMMU_LUT357L + 0x0008E7A0, // GFXMMU_LUT357H + 0x00700701, // GFXMMU_LUT358L + 0x0008EE40, // GFXMMU_LUT358H + 0x00700701, // GFXMMU_LUT359L + 0x0008F4E0, // GFXMMU_LUT359H + 0x00700701, // GFXMMU_LUT360L + 0x0008FB80, // GFXMMU_LUT360H + 0x006F0801, // GFXMMU_LUT361L + 0x00090210, // GFXMMU_LUT361H + 0x006F0801, // GFXMMU_LUT362L + 0x00090890, // GFXMMU_LUT362H + 0x006F0801, // GFXMMU_LUT363L + 0x00090F10, // GFXMMU_LUT363H + 0x006F0801, // GFXMMU_LUT364L + 0x00091590, // GFXMMU_LUT364H + 0x006F0801, // GFXMMU_LUT365L + 0x00091C10, // GFXMMU_LUT365H + 0x006F0801, // GFXMMU_LUT366L + 0x00092290, // GFXMMU_LUT366H + 0x006F0801, // GFXMMU_LUT367L + 0x00092910, // GFXMMU_LUT367H + 0x006E0901, // GFXMMU_LUT368L + 0x00092F80, // GFXMMU_LUT368H + 0x006E0901, // GFXMMU_LUT369L + 0x000935E0, // GFXMMU_LUT369H + 0x006E0901, // GFXMMU_LUT370L + 0x00093C40, // GFXMMU_LUT370H + 0x006E0901, // GFXMMU_LUT371L + 0x000942A0, // GFXMMU_LUT371H + 0x006E0901, // GFXMMU_LUT372L + 0x00094900, // GFXMMU_LUT372H + 0x006E0901, // GFXMMU_LUT373L + 0x00094F60, // GFXMMU_LUT373H + 0x006D0A01, // GFXMMU_LUT374L + 0x000955B0, // GFXMMU_LUT374H + 0x006D0A01, // GFXMMU_LUT375L + 0x00095BF0, // GFXMMU_LUT375H + 0x006D0A01, // GFXMMU_LUT376L + 0x00096230, // GFXMMU_LUT376H + 0x006D0A01, // GFXMMU_LUT377L + 0x00096870, // GFXMMU_LUT377H + 0x006D0A01, // GFXMMU_LUT378L + 0x00096EB0, // GFXMMU_LUT378H + 0x006C0B01, // GFXMMU_LUT379L + 0x000974E0, // GFXMMU_LUT379H + 0x006C0B01, // GFXMMU_LUT380L + 0x00097B00, // GFXMMU_LUT380H + 0x006C0B01, // GFXMMU_LUT381L + 0x00098120, // GFXMMU_LUT381H + 0x006C0B01, // GFXMMU_LUT382L + 0x00098740, // GFXMMU_LUT382H + 0x006C0B01, // GFXMMU_LUT383L + 0x00098D60, // GFXMMU_LUT383H + 0x006C0B01, // GFXMMU_LUT384L + 0x00099380, // GFXMMU_LUT384H + 0x006B0C01, // GFXMMU_LUT385L + 0x00099990, // GFXMMU_LUT385H + 0x006B0C01, // GFXMMU_LUT386L + 0x00099F90, // GFXMMU_LUT386H + 0x006B0C01, // GFXMMU_LUT387L + 0x0009A590, // GFXMMU_LUT387H + 0x006B0C01, // GFXMMU_LUT388L + 0x0009AB90, // GFXMMU_LUT388H + 0x006B0C01, // GFXMMU_LUT389L + 0x0009B190, // GFXMMU_LUT389H + 0x006A0D01, // GFXMMU_LUT390L + 0x0009B780, // GFXMMU_LUT390H + 0x006A0D01, // GFXMMU_LUT391L + 0x0009BD60, // GFXMMU_LUT391H + 0x006A0D01, // GFXMMU_LUT392L + 0x0009C340, // GFXMMU_LUT392H + 0x006A0D01, // GFXMMU_LUT393L + 0x0009C920, // GFXMMU_LUT393H + 0x006A0D01, // GFXMMU_LUT394L + 0x0009CF00, // GFXMMU_LUT394H + 0x00690E01, // GFXMMU_LUT395L + 0x0009D4D0, // GFXMMU_LUT395H + 0x00690E01, // GFXMMU_LUT396L + 0x0009DA90, // GFXMMU_LUT396H + 0x00690E01, // GFXMMU_LUT397L + 0x0009E050, // GFXMMU_LUT397H + 0x00690E01, // GFXMMU_LUT398L + 0x0009E610, // GFXMMU_LUT398H + 0x00690E01, // GFXMMU_LUT399L + 0x0009EBD0, // GFXMMU_LUT399H + 0x00690E01, // GFXMMU_LUT400L + 0x0009F190, // GFXMMU_LUT400H + 0x00690E01, // GFXMMU_LUT401L + 0x0009F750, // GFXMMU_LUT401H + 0x00680F01, // GFXMMU_LUT402L + 0x0009FD00, // GFXMMU_LUT402H + 0x00680F01, // GFXMMU_LUT403L + 0x000A02A0, // GFXMMU_LUT403H + 0x00680F01, // GFXMMU_LUT404L + 0x000A0840, // GFXMMU_LUT404H + 0x00680F01, // GFXMMU_LUT405L + 0x000A0DE0, // GFXMMU_LUT405H + 0x00671001, // GFXMMU_LUT406L + 0x000A1370, // GFXMMU_LUT406H + 0x00671001, // GFXMMU_LUT407L + 0x000A18F0, // GFXMMU_LUT407H + 0x00671001, // GFXMMU_LUT408L + 0x000A1E70, // GFXMMU_LUT408H + 0x00671001, // GFXMMU_LUT409L + 0x000A23F0, // GFXMMU_LUT409H + 0x00661101, // GFXMMU_LUT410L + 0x000A2960, // GFXMMU_LUT410H + 0x00661101, // GFXMMU_LUT411L + 0x000A2EC0, // GFXMMU_LUT411H + 0x00661101, // GFXMMU_LUT412L + 0x000A3420, // GFXMMU_LUT412H + 0x00661101, // GFXMMU_LUT413L + 0x000A3980, // GFXMMU_LUT413H + 0x00651201, // GFXMMU_LUT414L + 0x000A3ED0, // GFXMMU_LUT414H + 0x00651201, // GFXMMU_LUT415L + 0x000A4410, // GFXMMU_LUT415H + 0x00651201, // GFXMMU_LUT416L + 0x000A4950, // GFXMMU_LUT416H + 0x00641301, // GFXMMU_LUT417L + 0x000A4E80, // GFXMMU_LUT417H + 0x00641301, // GFXMMU_LUT418L + 0x000A53A0, // GFXMMU_LUT418H + 0x00641301, // GFXMMU_LUT419L + 0x000A58C0, // GFXMMU_LUT419H + 0x00641301, // GFXMMU_LUT420L + 0x000A5DE0, // GFXMMU_LUT420H + 0x00631401, // GFXMMU_LUT421L + 0x000A62F0, // GFXMMU_LUT421H + 0x00631401, // GFXMMU_LUT422L + 0x000A67F0, // GFXMMU_LUT422H + 0x00631401, // GFXMMU_LUT423L + 0x000A6CF0, // GFXMMU_LUT423H + 0x00621501, // GFXMMU_LUT424L + 0x000A71E0, // GFXMMU_LUT424H + 0x00621501, // GFXMMU_LUT425L + 0x000A76C0, // GFXMMU_LUT425H + 0x00621501, // GFXMMU_LUT426L + 0x000A7BA0, // GFXMMU_LUT426H + 0x00621501, // GFXMMU_LUT427L + 0x000A8080, // GFXMMU_LUT427H + 0x00611601, // GFXMMU_LUT428L + 0x000A8550, // GFXMMU_LUT428H + 0x00611601, // GFXMMU_LUT429L + 0x000A8A10, // GFXMMU_LUT429H + 0x00611601, // GFXMMU_LUT430L + 0x000A8ED0, // GFXMMU_LUT430H + 0x00601701, // GFXMMU_LUT431L + 0x000A9380, // GFXMMU_LUT431H + 0x00601701, // GFXMMU_LUT432L + 0x000A9820, // GFXMMU_LUT432H + 0x00601701, // GFXMMU_LUT433L + 0x000A9CC0, // GFXMMU_LUT433H + 0x005F1801, // GFXMMU_LUT434L + 0x000AA150, // GFXMMU_LUT434H + 0x005F1801, // GFXMMU_LUT435L + 0x000AA5D0, // GFXMMU_LUT435H + 0x005F1801, // GFXMMU_LUT436L + 0x000AAA50, // GFXMMU_LUT436H + 0x005E1901, // GFXMMU_LUT437L + 0x000AAEC0, // GFXMMU_LUT437H + 0x005E1901, // GFXMMU_LUT438L + 0x000AB320, // GFXMMU_LUT438H + 0x005D1A01, // GFXMMU_LUT439L + 0x000AB770, // GFXMMU_LUT439H + 0x005D1A01, // GFXMMU_LUT440L + 0x000ABBB0, // GFXMMU_LUT440H + 0x005D1A01, // GFXMMU_LUT441L + 0x000ABFF0, // GFXMMU_LUT441H + 0x005C1B01, // GFXMMU_LUT442L + 0x000AC420, // GFXMMU_LUT442H + 0x005C1B01, // GFXMMU_LUT443L + 0x000AC840, // GFXMMU_LUT443H + 0x005B1C01, // GFXMMU_LUT444L + 0x000ACC50, // GFXMMU_LUT444H + 0x005B1C01, // GFXMMU_LUT445L + 0x000AD050, // GFXMMU_LUT445H + 0x005B1C01, // GFXMMU_LUT446L + 0x000AD450, // GFXMMU_LUT446H + 0x005A1D01, // GFXMMU_LUT447L + 0x000AD840, // GFXMMU_LUT447H + 0x005A1D01, // GFXMMU_LUT448L + 0x000ADC20, // GFXMMU_LUT448H + 0x00591E01, // GFXMMU_LUT449L + 0x000ADFF0, // GFXMMU_LUT449H + 0x00591E01, // GFXMMU_LUT450L + 0x000AE3B0, // GFXMMU_LUT450H + 0x00581F01, // GFXMMU_LUT451L + 0x000AE760, // GFXMMU_LUT451H + 0x00581F01, // GFXMMU_LUT452L + 0x000AEB00, // GFXMMU_LUT452H + 0x00572001, // GFXMMU_LUT453L + 0x000AEE90, // GFXMMU_LUT453H + 0x00572001, // GFXMMU_LUT454L + 0x000AF210, // GFXMMU_LUT454H + 0x00562101, // GFXMMU_LUT455L + 0x000AF580, // GFXMMU_LUT455H + 0x00562101, // GFXMMU_LUT456L + 0x000AF8E0, // GFXMMU_LUT456H + 0x00552201, // GFXMMU_LUT457L + 0x000AFC30, // GFXMMU_LUT457H + 0x00552201, // GFXMMU_LUT458L + 0x000AFF70, // GFXMMU_LUT458H + 0x00542301, // GFXMMU_LUT459L + 0x000B02A0, // GFXMMU_LUT459H + 0x00542301, // GFXMMU_LUT460L + 0x000B05C0, // GFXMMU_LUT460H + 0x00532401, // GFXMMU_LUT461L + 0x000B08D0, // GFXMMU_LUT461H + 0x00522501, // GFXMMU_LUT462L + 0x000B0BC0, // GFXMMU_LUT462H + 0x00522501, // GFXMMU_LUT463L + 0x000B0EA0, // GFXMMU_LUT463H + 0x00512601, // GFXMMU_LUT464L + 0x000B1170, // GFXMMU_LUT464H + 0x00502701, // GFXMMU_LUT465L + 0x000B1420, // GFXMMU_LUT465H + 0x00502701, // GFXMMU_LUT466L + 0x000B16C0, // GFXMMU_LUT466H + 0x004F2801, // GFXMMU_LUT467L + 0x000B1950, // GFXMMU_LUT467H + 0x004E2901, // GFXMMU_LUT468L + 0x000B1BC0, // GFXMMU_LUT468H + 0x004D2A01, // GFXMMU_LUT469L + 0x000B1E10, // GFXMMU_LUT469H + 0x004D2A01, // GFXMMU_LUT470L + 0x000B2050, // GFXMMU_LUT470H + 0x004C2B01, // GFXMMU_LUT471L + 0x000B2280, // GFXMMU_LUT471H + 0x004B2C01, // GFXMMU_LUT472L + 0x000B2490, // GFXMMU_LUT472H + 0x004A2D01, // GFXMMU_LUT473L + 0x000B2680, // GFXMMU_LUT473H + 0x00492E01, // GFXMMU_LUT474L + 0x000B2850, // GFXMMU_LUT474H + 0x00482F01, // GFXMMU_LUT475L + 0x000B2A00, // GFXMMU_LUT475H + 0x00463101, // GFXMMU_LUT476L + 0x000B2B80, // GFXMMU_LUT476H + 0x00453201, // GFXMMU_LUT477L + 0x000B2CD0, // GFXMMU_LUT477H + 0x00433401, // GFXMMU_LUT478L + 0x000B2DF0, // GFXMMU_LUT478H + 0x00413601, // GFXMMU_LUT479L + 0x000B2ED0 // GFXMMU_LUT479H +}; + +#ifdef __cplusplus +} +#endif +#endif /*__ gfxmmu_lut_H */ + +/** + * @} + */ + +/** + * @} + */ diff --git a/core/embed/trezorhal/stm32u5/displays/panels/lx154a2422.c b/core/embed/trezorhal/stm32u5/displays/panels/lx154a2422.c new file mode 120000 index 00000000000..9a067993435 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/panels/lx154a2422.c @@ -0,0 +1 @@ +../../../stm32f4/displays/panels/lx154a2422.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/displays/panels/lx154a2422.h b/core/embed/trezorhal/stm32u5/displays/panels/lx154a2422.h new file mode 120000 index 00000000000..3bff068489d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/panels/lx154a2422.h @@ -0,0 +1 @@ +../../../stm32f4/displays/panels/lx154a2422.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/displays/st7789v.c b/core/embed/trezorhal/stm32u5/displays/st7789v.c new file mode 120000 index 00000000000..5f8dcd4cb6e --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/st7789v.c @@ -0,0 +1 @@ +../../stm32f4/displays/st7789v.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/displays/st7789v.h b/core/embed/trezorhal/stm32u5/displays/st7789v.h new file mode 120000 index 00000000000..7974c7d91f9 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/displays/st7789v.h @@ -0,0 +1 @@ +../../stm32f4/displays/st7789v.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/dma2d.c b/core/embed/trezorhal/stm32u5/dma2d.c new file mode 120000 index 00000000000..449adb75845 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/dma2d.c @@ -0,0 +1 @@ +../stm32f4/dma2d.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/fault_handlers.c b/core/embed/trezorhal/stm32u5/fault_handlers.c new file mode 100644 index 00000000000..3da1a165710 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/fault_handlers.c @@ -0,0 +1,36 @@ +#include "common.h" + +void fault_handlers_init(void) { + // Enable BUS fault and USAGE fault handlers + SCB->SHCSR |= (SCB_SHCSR_USGFAULTENA_Msk | SCB_SHCSR_BUSFAULTENA_Msk); +} + +void HardFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(HF)"); } + +void MemManage_Handler(void) { error_shutdown("INTERNAL ERROR", "(MM)"); } + +void BusFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(BF)"); } + +void UsageFault_Handler(void) { + if (SCB->CFSR & SCB_CFSR_STKOF_Msk) { + // Stack overflow + extern uint8_t _estack; // linker script symbol + // Fix stack pointer + __set_MSP((uint32_t)&_estack); + error_shutdown("INTERNAL ERROR", "(SO)"); + } else { + // Other error + error_shutdown("INTERNAL ERROR", "(UF)"); + } +} + +void SecureFault_Handler(void) { error_shutdown("INTERNAL ERROR", "(SF)"); } + +void GTZC_IRQHandler(void) { error_shutdown("INTERNAL ERROR", "(IA)"); } + +void NMI_Handler(void) { + // Clock Security System triggered NMI + if ((RCC->CIFR & RCC_CIFR_CSSF) != 0) { + error_shutdown("INTERNAL ERROR", "(CS)"); + } +} diff --git a/core/embed/trezorhal/stm32u5/flash.c b/core/embed/trezorhal/stm32u5/flash.c new file mode 100644 index 00000000000..9285336fc8a --- /dev/null +++ b/core/embed/trezorhal/stm32u5/flash.c @@ -0,0 +1,216 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include STM32_HAL_H + +#include +#include + +#include "common.h" +#include "flash.h" +#include "model.h" + +#ifdef STM32U585xx +#define FLASH_BANK_PAGES 128 +#define FLASH_SECTOR_COUNT (FLASH_BANK_PAGES * 2) +#else +#define FLASH_BANK_PAGES 256 +#define FLASH_SECTOR_COUNT (FLASH_BANK_PAGES * 2) +#endif + +#define FLASH_STATUS_ALL_FLAGS \ + (FLASH_NSSR_PGSERR | FLASH_NSSR_PGAERR | FLASH_NSSR_WRPERR | FLASH_NSSR_EOP) + +static bool flash_sector_is_secure(uint32_t sector) { + // We always return true since the entire flash memory is currently secure - + // partially through option bytes and partially through FLASH controller + // settings + return true; +} + +const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) { + if (sector >= FLASH_SECTOR_COUNT) { + return NULL; + } + + if (offset + size > FLASH_PAGE_SIZE) { + return NULL; + } + + uint32_t base_addr = + flash_sector_is_secure(sector) ? FLASH_BASE_S : FLASH_BASE_NS; + + return (const void *)(base_addr + FLASH_PAGE_SIZE * sector + offset); +} + +uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) { + if (first_sector + sector_count > FLASH_SECTOR_COUNT) { + return 0; + } + return FLASH_PAGE_SIZE * sector_count; +} + +uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) { + return first_sector + offset / FLASH_PAGE_SIZE; +} + +secbool flash_unlock_write(void) { + HAL_FLASH_Unlock(); + FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags +#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags +#endif + return sectrue; +} + +secbool flash_lock_write(void) { + HAL_FLASH_Lock(); + return sectrue; +} + +secbool flash_sector_erase(uint16_t sector) { + if (sector >= FLASH_SECTOR_COUNT) { + return secfalse; + } + + FLASH_EraseInitTypeDef EraseInitStruct = { + .TypeErase = FLASH_TYPEERASE_PAGES_NS, + .Banks = FLASH_BANK_1, + .Page = sector, + .NbPages = 1, + }; + + if (sector >= FLASH_BANK_PAGES) { + EraseInitStruct.Banks = FLASH_BANK_2; + EraseInitStruct.Page = sector - FLASH_BANK_PAGES; + } + + if (flash_sector_is_secure(sector)) { + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + } + + uint32_t sector_error = 0; + + if (HAL_FLASHEx_Erase(&EraseInitStruct, §or_error) != HAL_OK) { + return secfalse; + } + + // check whether the sector was really deleted (contains only 0xFF) + const uint32_t *sector_start = + (const uint32_t *)flash_get_address(sector, 0, 0); + + const uint32_t *sector_end = + sector_start + flash_sector_size(sector, 1) / sizeof(uint32_t); + + for (const uint32_t *addr = sector_start; addr < sector_end; addr++) { + if (*addr != 0xFFFFFFFF) { + return secfalse; + } + } + + return sectrue; +} + +secbool flash_write_quadword(uint16_t sector, uint32_t offset, + const uint32_t *data) { + uint32_t address = + (uint32_t)flash_get_address(sector, offset, 4 * sizeof(uint32_t)); + if (address == 0) { + return secfalse; + } + if (offset % (4 * sizeof(uint32_t))) { // we write only at 16-byte boundary + return secfalse; + } + + for (int i = 0; i < 4; i++) { + if (data[i] != (data[i] & *((const uint32_t *)address + i))) { + return secfalse; + } + } + + secbool all_match = sectrue; + for (int i = 0; i < 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + all_match = secfalse; + break; + } + } + if (all_match == sectrue) { + return sectrue; + } + + if (HAL_OK != + HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, address, (uint32_t)data)) { + return secfalse; + } + + for (int i = 0; i < 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_write_burst(uint16_t sector, uint32_t offset, + const uint32_t *data) { + uint32_t address = + (uint32_t)flash_get_address(sector, offset, 8 * 4 * sizeof(uint32_t)); + if (address == 0) { + return secfalse; + } + if (offset % + (8 * 4 * sizeof(uint32_t))) { // we write only at 16-byte boundary + return secfalse; + } + + for (int i = 0; i < 8 * 4; i++) { + if (data[i] != (data[i] & *((const uint32_t *)address + i))) { + return secfalse; + } + } + + secbool all_match = sectrue; + for (int i = 0; i < 8 * 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + all_match = secfalse; + break; + } + } + if (all_match == sectrue) { + return sectrue; + } + + if (HAL_OK != + HAL_FLASH_Program(FLASH_TYPEPROGRAM_BURST, address, (uint32_t)data)) { + return secfalse; + } + + for (int i = 0; i < 8 * 4; i++) { + if (data[i] != *((const uint32_t *)address + i)) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_write_block(uint16_t sector, uint32_t offset, + const flash_block_t block) { + return flash_write_quadword(sector, offset, block); +} diff --git a/core/embed/trezorhal/stm32u5/flash_otp.c b/core/embed/trezorhal/stm32u5/flash_otp.c new file mode 100644 index 00000000000..c5c6d7aa618 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/flash_otp.c @@ -0,0 +1,92 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include STM32_HAL_H + +#include "flash_otp.h" +#include "common.h" +#include "flash.h" + +void flash_otp_init() { + // intentionally left empty +} + +secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, + uint8_t datalen) { + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return secfalse; + } + for (uint8_t i = 0; i < datalen; i++) { + data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + + offset + i); + } + return sectrue; +} + +secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, + uint8_t datalen) { + if (datalen % 16 != 0) { + return secfalse; + } + if (block >= FLASH_OTP_NUM_BLOCKS || + offset + datalen > FLASH_OTP_BLOCK_SIZE) { + return secfalse; + } + ensure(flash_unlock_write(), NULL); + for (uint8_t i = 0; i < datalen; i += 16) { + uint32_t address = + FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; + ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD_NS, + address, (uint32_t)&data[i])), + NULL); + } + ensure(flash_lock_write(), NULL); + return sectrue; +} + +secbool flash_otp_lock(uint8_t block) { + // check that all quadwords in the block have been written to + volatile uint8_t *addr = + (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE); + + secbool qw_locked = secfalse; + for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) { + if (addr[i] != 0xFF) { + qw_locked = sectrue; + } + if (i % 16 == 15 && qw_locked == secfalse) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_otp_is_locked(uint8_t block) { + // considering block locked if any quadword in the block is non-0xFF + volatile uint8_t *addr = + (__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE); + + for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) { + if (addr[i] != 0xFF) { + return sectrue; + } + } + return secfalse; +} diff --git a/core/embed/trezorhal/stm32u5/haptic/drv2625/actuators/vg1040003d.h b/core/embed/trezorhal/stm32u5/haptic/drv2625/actuators/vg1040003d.h new file mode 100644 index 00000000000..e18e836aa1d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/haptic/drv2625/actuators/vg1040003d.h @@ -0,0 +1,6 @@ + +#define ACTUATOR_LRA +#define ACTUATOR_OPEN_LOOP + +#define ACTUATOR_LRA_PERIOD (239) +#define ACTUATOR_OD_CLAMP (126) diff --git a/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c new file mode 100644 index 00000000000..4134cc51ea8 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c @@ -0,0 +1,193 @@ +#include "drv2625_lib.h" +#include "haptic.h" + +#include + +#include STM32_HAL_H + +#include "i2c.h" +#include TREZOR_BOARD +#include HAPTIC_ACTUATOR + +#define DRV2625_I2C_ADDRESS (0x5A << 1) + +#define DRV2625_REG_CHIPID 0x00 +#define DRV2625_REG_STATUS 0x01 +#define DRV2625_REG_MODE 0x07 +#define DRV2625_REG_MODE_RTP 0 +#define DRV2625_REG_MODE_WAVEFORM 0x01 +#define DRV2625_REG_MODE_DIAG 0x02 +#define DRV2625_REG_MODE_AUTOCAL 0x03 +#define DRV2625_REG_MODE_TRGFUNC_PULSE 0x00 +#define DRV2625_REG_MODE_TRGFUNC_ENABLE 0x04 +#define DRV2625_REG_MODE_TRGFUNC_INTERRUPT 0x08 + +#define DRV2625_REG_LRAERM 0x08 +#define DRV2625_REG_LRAERM_LRA 0x80 +#define DRV2625_REG_LRAERM_OPENLOOP 0x40 +#define DRV2625_REG_LRAERM_AUTO_BRK_OL 0x10 +#define DRV2625_REG_LRAERM_AUTO_BRK_STBY 0x08 + +#define DRV2625_REG_LIBRARY 0x0D ///< Waveform library selection register +#define DRV2625_REG_LIBRARY_OPENLOOP 0x40 +#define DRV2625_REG_LIBRARY_GAIN_100 0x00 +#define DRV2625_REG_LIBRARY_GAIN_75 0x01 +#define DRV2625_REG_LIBRARY_GAIN_50 0x02 +#define DRV2625_REG_LIBRARY_GAIN_25 0x03 + +#define DRV2625_REG_RTP 0x0E ///< RTP input register + +#define DRV2625_REG_WAVESEQ1 0x0F ///< Waveform sequence register 1 +#define DRV2625_REG_WAVESEQ2 0x10 ///< Waveform sequence register 2 +#define DRV2625_REG_WAVESEQ3 0x11 ///< Waveform sequence register 3 +#define DRV2625_REG_WAVESEQ4 0x12 ///< Waveform sequence register 4 +#define DRV2625_REG_WAVESEQ5 0x13 ///< Waveform sequence register 5 +#define DRV2625_REG_WAVESEQ6 0x14 ///< Waveform sequence register 6 +#define DRV2625_REG_WAVESEQ7 0x15 ///< Waveform sequence register 7 +#define DRV2625_REG_WAVESEQ8 0x16 ///< Waveform sequence register 8 + +#define DRV2625_REG_GO 0x0C ///< Go register +#define DRV2625_REG_GO_GO 0x01 + +#define DRV2625_REG_OD_CLAMP 0x20 + +#define DRV2625_REG_LRA_WAVE_SHAPE 0x2C +#define DRV2625_REG_LRA_WAVE_SHAPE_SINE 0x01 + +#define DRV2625_REG_OL_LRA_PERIOD_LO 0x2F +#define DRV2625_REG_OL_LRA_PERIOD_HI 0x2E + +#if defined ACTUATOR_CLOSED_LOOP +#define LIB_SEL 0x00 +#define LOOP_SEL 0x00 +#elif defined ACTUATOR_OPEN_LOOP +#define LIB_SEL DRV2625_REG_LIBRARY_OPENLOOP +#define LOOP_SEL DRV2625_REG_LRAERM_OPENLOOP +#else +#error "Must define either CLOSED_LOOP or OPEN_LOOP" +#endif + +#if defined ACTUATOR_LRA +#define LRA_ERM_SEL DRV2625_REG_LRAERM_LRA +#elif defined ACTUATOR_ERM +#define LRA_ERM_SEL 0x00 +#else +#error "Must define either LRA or ERM" +#endif + +#define PRESS_EFFECT_AMPLITUDE 25 +#define PRESS_EFFECT_DURATION 10 + +#define PRODTEST_EFFECT_AMPLITUDE 127 + +static bool set_reg(uint8_t addr, uint8_t value) { + uint8_t data[] = {addr, value}; + return i2c_transmit(DRV2625_I2C_INSTANCE, DRV2625_I2C_ADDRESS, data, + sizeof(data), 1) == HAL_OK; +} + +void haptic_calibrate(void) { + set_reg(DRV2625_REG_MODE, DRV2625_REG_MODE_AUTOCAL); + HAL_Delay(1); + set_reg(DRV2625_REG_GO, DRV2625_REG_GO_GO); + + HAL_Delay(3000); +} + +void haptic_init(void) { + // select library + set_reg(DRV2625_REG_LIBRARY, LIB_SEL | DRV2625_REG_LIBRARY_GAIN_25); + set_reg(DRV2625_REG_LRAERM, + LRA_ERM_SEL | LOOP_SEL | DRV2625_REG_LRAERM_AUTO_BRK_OL); + + set_reg(DRV2625_REG_OD_CLAMP, ACTUATOR_OD_CLAMP); + + set_reg(DRV2625_REG_LRA_WAVE_SHAPE, DRV2625_REG_LRA_WAVE_SHAPE_SINE); + + set_reg(DRV2625_REG_OL_LRA_PERIOD_LO, ACTUATOR_LRA_PERIOD & 0xFF); + set_reg(DRV2625_REG_OL_LRA_PERIOD_HI, ACTUATOR_LRA_PERIOD >> 8); + + GPIO_InitTypeDef GPIO_InitStructure; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = GPIO_PIN_8; + GPIO_InitStructure.Alternate = GPIO_AF14_TIM16; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + + TIM_HandleTypeDef TIM_Handle; + __HAL_RCC_TIM16_CLK_ENABLE(); + TIM_Handle.State = HAL_TIM_STATE_RESET; + TIM_Handle.Instance = TIM16; + TIM_Handle.Init.Period = 0; + TIM_Handle.Init.Prescaler = SystemCoreClock / 10000; + TIM_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; + TIM_Handle.Init.RepetitionCounter = 0; + HAL_TIM_PWM_Init(&TIM_Handle); + + TIM_OC_InitTypeDef TIM_OC_InitStructure; + TIM_OC_InitStructure.OCMode = TIM_OCMODE_PWM2; + TIM_OC_InitStructure.OCPolarity = TIM_OCPOLARITY_HIGH; + TIM_OC_InitStructure.Pulse = 1; + TIM_OC_InitStructure.OCNPolarity = TIM_OCNPOLARITY_HIGH; + TIM_OC_InitStructure.OCFastMode = TIM_OCFAST_DISABLE; + HAL_TIM_PWM_ConfigChannel(&TIM_Handle, &TIM_OC_InitStructure, TIM_CHANNEL_1); + + HAL_TIM_OC_Start(&TIM_Handle, TIM_CHANNEL_1); + + TIM16->CR1 |= TIM_CR1_OPM; + TIM16->BDTR |= TIM_BDTR_MOE; +} + +static bool haptic_play_RTP(int8_t amplitude, uint16_t duration_ms) { + if (!set_reg(DRV2625_REG_MODE, + DRV2625_REG_MODE_RTP | DRV2625_REG_MODE_TRGFUNC_ENABLE)) { + return false; + } + + if (!set_reg(DRV2625_REG_RTP, (uint8_t)amplitude)) { + return false; + } + + if (duration_ms > 6500) { + duration_ms = 6500; + } + if (duration_ms == 0) { + return true; + } + + TIM16->CNT = 1; + TIM16->CCR1 = 1; + TIM16->ARR = duration_ms * 10; + TIM16->CR1 |= TIM_CR1_CEN; + + return true; +} + +static void haptic_play_lib(drv2625_lib_effect_t effect) { + set_reg(DRV2625_REG_MODE, DRV2625_REG_MODE_WAVEFORM); + set_reg(DRV2625_REG_WAVESEQ1, effect); + set_reg(DRV2625_REG_WAVESEQ2, 0); + set_reg(DRV2625_REG_GO, DRV2625_REG_GO_GO); +} + +void haptic_play(haptic_effect_t effect) { + switch (effect) { + case HAPTIC_BUTTON_PRESS: + haptic_play_RTP(PRESS_EFFECT_AMPLITUDE, PRESS_EFFECT_DURATION); + break; + case HAPTIC_ALERT: + haptic_play_lib(ALERT_750MS_100); + break; + case HAPTIC_HOLD_TO_CONFIRM: + haptic_play_lib(TRANSITION_RAMP_UP_SHORT_SMOOTH_1); + break; + default: + break; + } +} + +bool haptic_test(uint16_t duration_ms) { + return haptic_play_RTP(PRODTEST_EFFECT_AMPLITUDE, duration_ms); +} diff --git a/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625_lib.h b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625_lib.h new file mode 100644 index 00000000000..dcf449f443f --- /dev/null +++ b/core/embed/trezorhal/stm32u5/haptic/drv2625/drv2625_lib.h @@ -0,0 +1,130 @@ +#ifndef __DRV_2625_LIB_H__ +#define __DRV_2625_LIB_H__ + +typedef enum { + STRONG_CLICK_100 = 1, + STRONG_CLICK_60 = 2, + STRONG_CLICK_30 = 3, + SHARP_CLICK_100 = 4, + SHARP_CLICK_60 = 5, + SHARP_CLICK_30 = 6, + SOFT_BUMP_100 = 7, + SOFT_BUMP_60 = 8, + SOFT_BUMP_30 = 9, + DOUBLE_CLICK_100 = 10, + DOUBLE_CLICK_60 = 11, + TRIPLE_CLICK_100 = 12, + SOFT_FUZZ_60 = 13, + STRONG_BUZZ_100 = 14, + ALERT_750MS_100 = 15, + ALERT_1000MS_100 = 16, + STRONG_CLICK_1_100 = 17, + STRONG_CLICK_2_80 = 18, + STRONG_CLICK_3_60 = 19, + STRONG_CLICK_4_30 = 20, + MEDIUM_CLICK_1_100 = 21, + MEDIUM_CLICK_2_80 = 22, + MEDIUM_CLICK_3_60 = 23, + SHARP_TICK_1_100 = 24, + SHARP_TICK_2_80 = 25, + SHARP_TICK_3_60 = 26, + SHORT_DOUBLE_CLICK_STRONG_1_100 = 27, + SHORT_DOUBLE_CLICK_STRONG_2_80 = 28, + SHORT_DOUBLE_CLICK_STRONG_3_60 = 29, + SHORT_DOUBLE_CLICK_STRONG_4_30 = 30, + SHORT_DOUBLE_CLICK_MEDIUM_1_100 = 31, + SHORT_DOUBLE_CLICK_MEDIUM_2_80 = 32, + SHORT_DOUBLE_CLICK_MEDIUM_3_60 = 33, + SHORT_DOUBLE_SHARP_TICK_1_100 = 34, + SHORT_DOUBLE_SHARP_TICK_2_80 = 35, + SHORT_DOUBLE_SHARP_TICK_3_60 = 36, + LONG_DOUBLE_SHARP_TICK_STRONG_1_100 = 37, + LONG_DOUBLE_SHARP_TICK_STRONG_2_80 = 38, + LONG_DOUBLE_SHARP_TICK_STRONG_3_60 = 39, + LONG_DOUBLE_SHARP_TICK_STRONG_4_30 = 40, + LONG_DOUBLE_SHARP_TICK_MEDIUM_1_100 = 41, + LONG_DOUBLE_SHARP_TICK_MEDIUM_2_80 = 42, + LONG_DOUBLE_SHARP_TICK_MEDIUM_3_60 = 43, + LONG_DOUBLE_SHARP_TICK_1_100 = 44, + LONG_DOUBLE_SHARP_TICK_2_80 = 45, + LONG_DOUBLE_SHARP_TICK_3_60 = 46, + BUZZ_1_100 = 47, + BUZZ_2_80 = 48, + BUZZ_3_60 = 49, + BUZZ_4_40 = 50, + BUZZ_5_20 = 51, + PULSING_STRONG_1_100 = 52, + PULSING_STRONG_2_60 = 53, + PULSING_MEDIUM_1_100 = 54, + PULSING_MEDIUM_2_60 = 55, + PULSING_SHARP_1_100 = 56, + PULSING_SHARP_2_60 = 57, + TRANSITION_CLICK_1_100 = 58, + TRANSITION_CLICK_2_80 = 59, + TRANSITION_CLICK_3_60 = 60, + TRANSITION_CLICK_4_40 = 61, + TRANSITION_CLICK_5_20 = 62, + TRANSITION_CLICK_6_10 = 63, + TRANSITION_HUM_1_100 = 64, + TRANSITION_HUM_2_80 = 65, + TRANSITION_HUM_3_60 = 66, + TRANSITION_HUM_4_40 = 67, + TRANSITION_HUM_5_20 = 68, + TRANSITION_HUM_6_10 = 69, + TRANSITION_RAMP_DOWN_LONG_SMOOTH_1 = 70, + TRANSITION_RAMP_DOWN_LONG_SMOOTH_2 = 71, + TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_1 = 72, + TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_2 = 73, + TRANSITION_RAMP_DOWN_SHORT_SMOOTH_1 = 74, + TRANSITION_RAMP_DOWN_SHORT_SMOOTH_2 = 75, + TRANSITION_RAMP_DOWN_LONG_SHARP_1 = 76, + TRANSITION_RAMP_DOWN_LONG_SHARP_2 = 77, + TRANSITION_RAMP_DOWN_MEDIUM_SHARP_1 = 78, + TRANSITION_RAMP_DOWN_MEDIUM_SHARP_2 = 79, + TRANSITION_RAMP_DOWN_SHORT_SHARP_1 = 80, + TRANSITION_RAMP_DOWN_SHORT_SHARP_2 = 81, + TRANSITION_RAMP_UP_LONG_SMOOTH_1 = 82, + TRANSITION_RAMP_UP_LONG_SMOOTH_2 = 83, + TRANSITION_RAMP_UP_MEDIUM_SMOOTH_1 = 84, + TRANSITION_RAMP_UP_MEDIUM_SMOOTH_2 = 85, + TRANSITION_RAMP_UP_SHORT_SMOOTH_1 = 86, + TRANSITION_RAMP_UP_SHORT_SMOOTH_2 = 87, + TRANSITION_RAMP_UP_LONG_SHARP_1 = 88, + TRANSITION_RAMP_UP_LONG_SHARP_2 = 89, + TRANSITION_RAMP_UP_MEDIUM_SHARP_1 = 90, + TRANSITION_RAMP_UP_MEDIUM_SHARP_2 = 91, + TRANSITION_RAMP_UP_SHORT_SHARP_1 = 92, + TRANSITION_RAMP_UP_SHORT_SHARP_2 = 93, + TRANSITION_RAMP_DOWN_LONG_SMOOTH_1_50 = 94, + TRANSITION_RAMP_DOWN_LONG_SMOOTH_2_50 = 95, + TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_1_50 = 96, + TRANSITION_RAMP_DOWN_MEDIUM_SMOOTH_2_50 = 97, + TRANSITION_RAMP_DOWN_SHORT_SMOOTH_1_50 = 98, + TRANSITION_RAMP_DOWN_SHORT_SMOOTH_2_50 = 99, + TRANSITION_RAMP_DOWN_LONG_SHARP_1_50 = 100, + TRANSITION_RAMP_DOWN_LONG_SHARP_2_50 = 101, + TRANSITION_RAMP_DOWN_MEDIUM_SHARP_1_50 = 102, + TRANSITION_RAMP_DOWN_MEDIUM_SHARP_2_50 = 103, + TRANSITION_RAMP_DOWN_SHORT_SHARP_1_50 = 104, + TRANSITION_RAMP_DOWN_SHORT_SHARP_2_50 = 105, + TRANSITION_RAMP_UP_LONG_SMOOTH_1_50 = 106, + TRANSITION_RAMP_UP_LONG_SMOOTH_2_50 = 107, + TRANSITION_RAMP_UP_MEDIUM_SMOOTH_1_50 = 108, + TRANSITION_RAMP_UP_MEDIUM_SMOOTH_2_50 = 109, + TRANSITION_RAMP_UP_SHORT_SMOOTH_1_50 = 110, + TRANSITION_RAMP_UP_SHORT_SMOOTH_2_50 = 111, + TRANSITION_RAMP_UP_LONG_SHARP_1_50 = 112, + TRANSITION_RAMP_UP_LONG_SHARP_2_50 = 113, + TRANSITION_RAMP_UP_MEDIUM_SHARP_1_50 = 114, + TRANSITION_RAMP_UP_MEDIUM_SHARP_2_50 = 115, + TRANSITION_RAMP_UP_SHORT_SHARP_1_50 = 116, + TRANSITION_RAMP_UP_SHORT_SHARP_2_50 = 117, + LONG_BUZZ_FROM_PROGRAMMATIC_STOPPING = 118, + SMOOTH_HUM_1_100 = 119, + SMOOTH_HUM_2_80 = 120, + SMOOTH_HUM_3_60 = 121, + SMOOTH_HUM_4_40 = 122, + SMOOTH_HUM_5_20 = 123, +} drv2625_lib_effect_t; + +#endif diff --git a/core/embed/trezorhal/stm32u5/hash_processor.c b/core/embed/trezorhal/stm32u5/hash_processor.c new file mode 100644 index 00000000000..390b2426b12 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/hash_processor.c @@ -0,0 +1,132 @@ +#include "hash_processor.h" +#include +#include +#include STM32_HAL_H +#include "irq.h" +#include "memzero.h" +#include "sha2.h" + +HASH_HandleTypeDef hhash = {0}; +DMA_HandleTypeDef DMA_Handle = {0}; + +void hash_processor_init(void) { + __HAL_RCC_HASH_CLK_ENABLE(); + __HAL_RCC_GPDMA1_CLK_ENABLE(); + + hhash.Init.DataType = HASH_DATATYPE_8B; + hhash.hdmain = &DMA_Handle; + HAL_HASH_Init(&hhash); + + /* USER CODE END GPDMA1_Init 1 */ + DMA_Handle.Instance = GPDMA1_Channel12; + DMA_Handle.Init.Request = GPDMA1_REQUEST_HASH_IN; + DMA_Handle.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; + DMA_Handle.Init.Direction = DMA_MEMORY_TO_PERIPH; + DMA_Handle.Init.SrcInc = DMA_SINC_INCREMENTED; + DMA_Handle.Init.DestInc = DMA_DINC_FIXED; + DMA_Handle.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_WORD; + DMA_Handle.Init.DestDataWidth = DMA_DEST_DATAWIDTH_WORD; + DMA_Handle.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; + DMA_Handle.Init.SrcBurstLength = 1; + DMA_Handle.Init.DestBurstLength = 4; + DMA_Handle.Init.TransferAllocatedPort = + DMA_SRC_ALLOCATED_PORT1 | DMA_DEST_ALLOCATED_PORT0; + DMA_Handle.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; + DMA_Handle.Init.Mode = DMA_NORMAL; + HAL_DMA_Init(&DMA_Handle); + HAL_DMA_ConfigChannelAttributes(&DMA_Handle, DMA_CHANNEL_SEC | + DMA_CHANNEL_SRC_SEC | + DMA_CHANNEL_DEST_SEC); + + DMA_Handle.Parent = &hhash; + + HAL_NVIC_SetPriority(GPDMA1_Channel12_IRQn, IRQ_PRI_DMA, 0); + HAL_NVIC_EnableIRQ(GPDMA1_Channel12_IRQn); +} + +void GPDMA1_Channel12_IRQHandler(void) { HAL_DMA_IRQHandler(&DMA_Handle); } + +static void hash_processor_sha256_calc_dma(const uint8_t *data, uint32_t len, + uint8_t *hash) { + while (len > 0) { + uint32_t chunk = len > 0x8000 ? 0x8000 : len; + bool last = (len - chunk) <= 0; + + __HAL_HASH_SET_MDMAT(); + + HAL_HASHEx_SHA256_Start_DMA(&hhash, (uint8_t *)data, chunk); + while (HAL_HASH_GetState(&hhash) != HAL_HASH_STATE_READY) + ; + + if (last) { + HASH->STR |= HASH_STR_DCAL; + HAL_HASHEx_SHA256_Finish(&hhash, hash, 1000); + } + data += chunk; + len -= chunk; + } +} + +void hash_processor_sha256_calc(const uint8_t *data, uint32_t len, + uint8_t *hash) { + if (((uint32_t)data & 0x3) == 0) { + hash_processor_sha256_calc_dma(data, len, hash); + } else { + HAL_HASHEx_SHA256_Start(&hhash, (uint8_t *)data, len, hash, 1000); + } +} + +void hash_processor_sha256_init(hash_sha265_context_t *ctx) { + memzero(ctx, sizeof(hash_sha265_context_t)); +} + +void hash_processor_sha256_update(hash_sha265_context_t *ctx, + const uint8_t *data, uint32_t len) { + if (ctx->length > 0) { + uint32_t chunk = HASH_SHA256_BUFFER_SIZE - ctx->length; + if (chunk > len) { + chunk = len; + } + memcpy(ctx->buffer + ctx->length, data, chunk); + ctx->length += chunk; + data += chunk; + len -= chunk; + if (ctx->length == HASH_SHA256_BUFFER_SIZE) { + HAL_HASHEx_SHA256_Accmlt(&hhash, (uint8_t *)ctx->buffer, + HASH_SHA256_BUFFER_SIZE); + ctx->length = 0; + memzero(ctx->buffer, HASH_SHA256_BUFFER_SIZE); + } + } + + uint32_t len_aligned = len & ~(HASH_SHA256_BUFFER_SIZE - 1); + uint32_t len_rest = len & (HASH_SHA256_BUFFER_SIZE - 1); + + while (len_aligned > 0) { + uint32_t chunk = len_aligned > 0x8000 ? 0x8000 : len_aligned; + HAL_HASHEx_SHA256_Accmlt(&hhash, (uint8_t *)data, chunk); + data += chunk; + len_aligned -= chunk; + } + + if (len_rest > 0) { + memcpy(ctx->buffer, data, len_rest); + ctx->length = len_rest; + } +} + +void hash_processor_sha256_final(hash_sha265_context_t *ctx, uint8_t *output) { + uint32_t tmp_out[SHA256_DIGEST_LENGTH / sizeof(uint32_t)] = {0}; + + if (ctx->length > 0) { + memzero(ctx->buffer + ctx->length, HASH_SHA256_BUFFER_SIZE - ctx->length); + HAL_HASHEx_SHA256_Accmlt_End(&hhash, (uint8_t *)ctx->buffer, ctx->length, + (uint8_t *)tmp_out, 1000); + ctx->length = 0; + memzero(ctx->buffer, HASH_SHA256_BUFFER_SIZE); + } else { + HASH->STR |= HASH_STR_DCAL; + HAL_HASHEx_SHA256_Finish(&hhash, (uint8_t *)tmp_out, 1000); + } + memcpy(output, tmp_out, SHA256_DIGEST_LENGTH); +} diff --git a/core/embed/trezorhal/stm32u5/i2c.c b/core/embed/trezorhal/stm32u5/i2c.c new file mode 100644 index 00000000000..59163506e54 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/i2c.c @@ -0,0 +1,156 @@ + + +#include STM32_HAL_H +#include TREZOR_BOARD +#include "i2c.h" +#include "common.h" + +static I2C_HandleTypeDef i2c_handle[I2C_COUNT]; + +typedef struct { + I2C_TypeDef *Instance; + GPIO_TypeDef *SclPort; + GPIO_TypeDef *SdaPort; + uint16_t SclPin; + uint16_t SdaPin; + uint8_t PinAF; + volatile uint32_t *ResetReg; + uint32_t ResetBit; +} i2c_instance_t; + +i2c_instance_t i2c_defs[I2C_COUNT] = { + { + .Instance = I2C_INSTANCE_0, + .SclPort = I2C_INSTANCE_0_SCL_PORT, + .SdaPort = I2C_INSTANCE_0_SDA_PORT, + .SclPin = I2C_INSTANCE_0_SCL_PIN, + .SdaPin = I2C_INSTANCE_0_SDA_PIN, + .PinAF = I2C_INSTANCE_0_PIN_AF, + .ResetReg = I2C_INSTANCE_0_RESET_REG, + .ResetBit = I2C_INSTANCE_0_RESET_BIT, + }, +#ifdef I2C_INSTANCE_1 + { + .Instance = I2C_INSTANCE_1, + .SclPort = I2C_INSTANCE_1_SCL_PORT, + .SdaPort = I2C_INSTANCE_1_SDA_PORT, + .SclPin = I2C_INSTANCE_1_SCL_PIN, + .SdaPin = I2C_INSTANCE_1_SDA_PIN, + .PinAF = I2C_INSTANCE_1_PIN_AF, + .ResetReg = I2C_INSTANCE_1_RESET_REG, + .ResetBit = I2C_INSTANCE_1_RESET_BIT, + }, +#endif + +}; + +/* + * Using calculation from STM32CubeMX + * PCLKx as source, assumed 160MHz + * Fast mode, freq = 400kHz, Rise time = 250ns, Fall time = 100ns + */ +#define I2C_TIMING_400000_Hz 0x30D2153A + +void i2c_init_instance(uint16_t idx, i2c_instance_t *instance) { + if (i2c_handle[idx].Instance) { + return; + } + + GPIO_InitTypeDef GPIO_InitStructure; + + // configure CTP I2C SCL and SDA GPIO lines + GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = + GPIO_SPEED_FREQ_LOW; // I2C is a KHz bus and low speed is still good into + // the low MHz + + GPIO_InitStructure.Alternate = instance->PinAF; + GPIO_InitStructure.Pin = instance->SclPin; + HAL_GPIO_Init(instance->SclPort, &GPIO_InitStructure); + + GPIO_InitStructure.Alternate = instance->PinAF; + GPIO_InitStructure.Pin = instance->SdaPin; + HAL_GPIO_Init(instance->SdaPort, &GPIO_InitStructure); + + i2c_handle[idx].Instance = instance->Instance; + i2c_handle[idx].Init.Timing = I2C_TIMING_400000_Hz; + i2c_handle[idx].Init.OwnAddress1 = 0xFE; // master + i2c_handle[idx].Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + i2c_handle[idx].Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + i2c_handle[idx].Init.OwnAddress2 = 0; + i2c_handle[idx].Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + i2c_handle[idx].Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + + if (HAL_OK != HAL_I2C_Init(&i2c_handle[idx])) { + ensure(secfalse, "I2C was not loaded properly."); + return; + } +} + +void i2c_init(void) { + // enable I2C clock + I2C_INSTANCE_0_CLK_EN(); + I2C_INSTANCE_0_SCL_CLK_EN(); + I2C_INSTANCE_0_SDA_CLK_EN(); + i2c_init_instance(0, &i2c_defs[0]); + +#ifdef I2C_INSTANCE_1 + I2C_INSTANCE_1_CLK_EN(); + I2C_INSTANCE_1_SCL_CLK_EN(); + I2C_INSTANCE_1_SDA_CLK_EN(); + i2c_init_instance(1, &i2c_defs[1]); +#endif +} + +void i2c_deinit(uint16_t idx) { + if (i2c_handle[idx].Instance) { + HAL_I2C_DeInit(&i2c_handle[idx]); + i2c_handle[idx].Instance = NULL; + } +} + +void i2c_ensure_pin(GPIO_TypeDef *port, uint16_t GPIO_Pin, + GPIO_PinState PinState) { + HAL_GPIO_WritePin(port, GPIO_Pin, PinState); + while (HAL_GPIO_ReadPin(port, GPIO_Pin) != PinState) + ; +} + +void i2c_cycle(uint16_t idx) { + SET_BIT(*i2c_defs[idx].ResetReg, i2c_defs[idx].ResetBit); + CLEAR_BIT(*i2c_defs[idx].ResetReg, i2c_defs[idx].ResetBit); +} + +HAL_StatusTypeDef i2c_transmit(uint16_t idx, uint8_t addr, uint8_t *data, + uint16_t len, uint32_t timeout) { + return HAL_I2C_Master_Transmit(&i2c_handle[idx], addr, data, len, timeout); +} + +HAL_StatusTypeDef i2c_receive(uint16_t idx, uint8_t addr, uint8_t *data, + uint16_t len, uint32_t timeout) { + HAL_StatusTypeDef ret = + HAL_I2C_Master_Receive(&i2c_handle[idx], addr, data, len, timeout); +#ifdef USE_OPTIGA + if (idx == OPTIGA_I2C_INSTANCE) { + // apply GUARD_TIME as specified by the OPTIGA datasheet + // (only applies to the I2C bus to which the OPTIGA is connected) + hal_delay_us(50); + } +#endif + + return ret; +} + +HAL_StatusTypeDef i2c_mem_write(uint16_t idx, uint8_t addr, uint16_t mem_addr, + uint16_t mem_addr_size, uint8_t *data, + uint16_t len, uint32_t timeout) { + return HAL_I2C_Mem_Write(&i2c_handle[idx], addr, mem_addr, mem_addr_size, + data, len, timeout); +} +HAL_StatusTypeDef i2c_mem_read(uint16_t idx, uint8_t addr, uint16_t mem_addr, + uint16_t mem_addr_size, uint8_t *data, + uint16_t len, uint32_t timeout) { + return HAL_I2C_Mem_Read(&i2c_handle[idx], addr, mem_addr, mem_addr_size, data, + len, timeout); +} diff --git a/core/embed/trezorhal/stm32u5/i2c.h b/core/embed/trezorhal/stm32u5/i2c.h new file mode 120000 index 00000000000..d9235cabc4b --- /dev/null +++ b/core/embed/trezorhal/stm32u5/i2c.h @@ -0,0 +1 @@ +../stm32f4/i2c.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/irq.h b/core/embed/trezorhal/stm32u5/irq.h new file mode 120000 index 00000000000..f2c8e555e67 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/irq.h @@ -0,0 +1 @@ +../stm32f4/irq.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/limited_util.s b/core/embed/trezorhal/stm32u5/limited_util.s new file mode 100644 index 00000000000..b5dc918aeef --- /dev/null +++ b/core/embed/trezorhal/stm32u5/limited_util.s @@ -0,0 +1,133 @@ + .syntax unified + + .text + + .global memset_reg + .type memset_reg, STT_FUNC +memset_reg: + // call with the following (note that the arguments are not validated prior to use): + // r0 - address of first word to write (inclusive) + // r1 - address of first word following the address in r0 to NOT write (exclusive) + // r2 - word value to be written + // both addresses in r0 and r1 needs to be divisible by 4! + cmp r0, r1 + beq .L_loop_end + .L_loop_begin: + str r2, [r0], 4 // store the word in r2 to the address in r0, post-indexed + cmp r0, r1 + bne .L_loop_begin + .L_loop_end: + bx lr + + // Jump to address given in first argument R0 that points to next's stage's VTOR + // Clear memory and all registers before jump + .global jump_to + .type jump_to, STT_FUNC +jump_to: + mov r4, r0 // save input argument r0 (the address of the next stage's vector table) (r4 is callee save) + // this subroutine re-points the exception handlers before the C code + // that comprises them has been given a good environment to run. + // therefore, this code needs to disable interrupts before the VTOR + // update. then, the reset_handler of the next stage needs to re-enable interrupts. + // the following prevents activation of all exceptions except Non-Maskable Interrupt (NMI). + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.8: + // "there is no requirement to insert memory barrier instructions after CPSID". + cpsid f + // wipe memory at the end of the current stage of code + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + mov lr, r4 + // clear out the general purpose registers before the next stage's code can run (even the NMI exception handler) + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + // give the next stage a fresh main stack pointer + ldr r0, [lr] // set r0 to the main stack pointer in the next stage's vector table + msr msp, r0 // give the next stage its main stack pointer + // point to the next stage's exception handlers + // AN321, section 4.11: "a memory barrier is not required after a VTOR update" + .set SCB_VTOR, 0xE000ED08 // reference "Cortex-M4 Devices Generic User Guide" section 4.3 + ldr r0, =SCB_VTOR + str lr, [r0] + mov r0, r1 // zero out r0 + // go on to the next stage + ldr lr, [lr, 4] // set lr to the next stage's reset_handler + bx lr + + + .global shutdown_privileged + .type shutdown_privileged, STT_FUNC + // The function must be called from the privileged mode +shutdown_privileged: + cpsid f // disable all exceptions (except for NMI), the instruction is ignored in unprivileged mode + // if the exceptions weren't disabled, an exception handler (for example systick handler) + // could be called after the memory is erased, which would lead to another exception + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + ldr lr, =0xffffffff + + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =1 + msr control, r0 // jump to unprivileged mode + ldr r0, =0 + b . // loop forever + + .end diff --git a/core/embed/trezorhal/stm32u5/lowlevel.c b/core/embed/trezorhal/stm32u5/lowlevel.c new file mode 100644 index 00000000000..3a716c1a734 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/lowlevel.c @@ -0,0 +1,345 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include STM32_HAL_H + +#include "lowlevel.h" +#include "common.h" +#include "flash.h" +#include "flash_otp.h" +#include "model.h" +#include TREZOR_BOARD + +#pragma GCC optimize( \ + "no-stack-protector") // applies to all functions in this file + +#if PRODUCTION +#define WANT_RDP_LEVEL (OB_RDP_LEVEL_2) +#define WANT_WRP_PAGE_START 2 +#define WANT_WRP_PAGE_END 7 +#else +#define WANT_RDP_LEVEL (OB_RDP_LEVEL_0) +#endif + +#ifdef VDD_3V3 +// BOR LEVEL 0: Reset level threshold is around 2.8 V +#define WANT_BOR_LEVEL (OB_BOR_LEVEL_4) +#define USE_PVD 1 +#elif VDD_1V8 +// BOR LEVEL 0: Reset level threshold is around 1.7 V +#define WANT_BOR_LEVEL (OB_BOR_LEVEL_0) +#else +#error "VDD_3V3 or VDD_1V8 must be defined" +#endif + +#if defined STM32U5A9xx | defined STM32U5G9xx +#define WRP_DEFAULT_VALUE 0xFF00FFFF +#define SEC_WM1R1_DEFAULT_VALUE 0xFF00FF00 +#define SEC_WM1R2_DEFAULT_VALUE 0x7F007F00 +#define SEC_AREA_1_PAGE_START 0 +#define HDP_AREA_1_PAGE_END 1 +#define SEC_AREA_1_PAGE_END 0x07 +#define SEC_AREA_2_PAGE_START 0xFF +#define SEC_AREA_2_PAGE_END 0x00 +#elif defined STM32U585xx +#define WRP_DEFAULT_VALUE 0xFF80FFFF +#define SEC_WM1R1_DEFAULT_VALUE 0xFF80FF80 +#define SEC_WM1R2_DEFAULT_VALUE 0x7F807F80 +#define SEC_AREA_1_PAGE_START 0 +#define HDP_AREA_1_PAGE_END 1 +#define SEC_AREA_1_PAGE_END 0x07 +#define SEC_AREA_2_PAGE_START 0x7F +#define SEC_AREA_2_PAGE_END 0x00 +#else +#error Unknown MCU +#endif + +#define FLASH_OPTR_VALUE \ + (FLASH_OPTR_TZEN | FLASH_OPTR_PA15_PUPEN | FLASH_OPTR_nBOOT0 | \ + FLASH_OPTR_SRAM3_ECC | FLASH_OPTR_BKPRAM_ECC | FLASH_OPTR_DUALBANK | \ + FLASH_OPTR_WWDG_SW | FLASH_OPTR_IWDG_STOP | FLASH_OPTR_IWDG_STDBY | \ + FLASH_OPTR_IWDG_SW | FLASH_OPTR_SRAM_RST | FLASH_OPTR_nRST_SHDW | \ + FLASH_OPTR_nRST_STDBY | FLASH_OPTR_nRST_STOP | WANT_BOR_LEVEL | \ + (WANT_RDP_LEVEL << FLASH_OPTR_RDP_Pos)) + +#define FALSH_SECBOOTADD0R_VALUE \ + ((BOARDLOADER_START & 0xFFFFFF80) | FLASH_SECBOOTADD0R_BOOT_LOCK | 0x7C) + +#define FLASH_SECWM1R1_VALUE \ + (SEC_AREA_1_PAGE_START << FLASH_SECWM1R1_SECWM1_PSTRT_Pos | \ + SEC_AREA_1_PAGE_END << FLASH_SECWM1R1_SECWM1_PEND_Pos | \ + SEC_WM1R1_DEFAULT_VALUE) +#define FLASH_SECWM1R2_VALUE \ + (HDP_AREA_1_PAGE_END << FLASH_SECWM1R2_HDP1_PEND_Pos | \ + FLASH_SECWM1R2_HDP1EN | SEC_WM1R2_DEFAULT_VALUE) + +#define FLASH_SECWM2R1_VALUE \ + (SEC_AREA_2_PAGE_START << FLASH_SECWM1R1_SECWM1_PSTRT_Pos | \ + SEC_AREA_2_PAGE_END << FLASH_SECWM1R1_SECWM1_PEND_Pos | \ + SEC_WM1R1_DEFAULT_VALUE) +#define FLASH_SECWM2R2_VALUE (SEC_WM1R2_DEFAULT_VALUE) + +#define FLASH_STATUS_ALL_FLAGS \ + (FLASH_NSSR_PGSERR | FLASH_NSSR_PGAERR | FLASH_NSSR_WRPERR | FLASH_NSSR_EOP) + +static uint32_t flash_wait_and_clear_status_flags(void) { + while (FLASH->NSSR & FLASH_NSSR_BSY) + ; // wait for all previous flash operations to complete + + uint32_t result = + FLASH->NSSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags + FLASH->NSSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags + +#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + while (FLASH->SECSR & FLASH_SECSR_BSY) + ; // wait for all previous flash operations to complete + result |= + FLASH->SECSR & FLASH_STATUS_ALL_FLAGS; // get the current status flags + FLASH->SECSR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags +#endif + return result; +} + +secbool flash_check_option_bytes(void) { + flash_wait_and_clear_status_flags(); + // check values stored in flash interface registers + if (FLASH->OPTR != + FLASH_OPTR_VALUE) { // ignore bits 0 and 1 because they are control bits + return secfalse; + } + + if (FLASH->SECBOOTADD0R != FALSH_SECBOOTADD0R_VALUE) { + return secfalse; + } + +#if PRODUCTION + // TODO error this wont work, need to add default/reset values +#error this wont work, need to add default/reset values + if (FLASH->WRP1AR != (WANT_WRP_PAGE_START | (WANT_WRP_PAGE_END << 16))) { + return secfalse; + } +#else + if (FLASH->WRP1AR != WRP_DEFAULT_VALUE) { + return secfalse; + } +#endif + + if (FLASH->WRP1BR != WRP_DEFAULT_VALUE) { + return secfalse; + } + if (FLASH->WRP2AR != WRP_DEFAULT_VALUE) { + return secfalse; + } + if (FLASH->WRP2BR != WRP_DEFAULT_VALUE) { + return secfalse; + } + + return sectrue; +} + +void flash_lock_option_bytes(void) { + FLASH->NSCR |= FLASH_NSCR_OPTLOCK; // lock the option bytes +} + +void flash_unlock_option_bytes(void) { + if ((FLASH->NSCR & FLASH_NSCR_OPTLOCK) == 0) { + return; // already unlocked + } + // reference RM0090 section 3.7.2 + // write the special sequence to unlock + FLASH->OPTKEYR = FLASH_OPTKEY1; + FLASH->OPTKEYR = FLASH_OPTKEY2; + while (FLASH->NSCR & FLASH_NSCR_OPTLOCK) + ; // wait until the flash option control register is unlocked +} + +uint32_t flash_set_option_bytes(void) { + if (flash_unlock_write() != sectrue) { + return 0; + } + flash_wait_and_clear_status_flags(); + flash_unlock_option_bytes(); + flash_wait_and_clear_status_flags(); + + FLASH->OPTR = + FLASH_OPTR_VALUE; // WARNING: dev board safe unless you compile for + // PRODUCTION or change this value!!! + + FLASH->SECBOOTADD0R = FALSH_SECBOOTADD0R_VALUE; + +#if PRODUCTION + FLASH->WRP1AR = WANT_WRP_PAGE_START | (WANT_WRP_PAGE_END << 16); + FLASH->WRP1BR = 0xFF00FFFF; + FLASH->WRP2AR = 0xFF00FFFF; + FLASH->WRP2BR = 0xFF00FFFF; +#endif + + FLASH_WaitForLastOperation(HAL_MAX_DELAY); + + FLASH->NSCR |= FLASH_NSCR_OPTSTRT; + uint32_t result = + flash_wait_and_clear_status_flags(); // wait until changes are committed + + FLASH_WaitForLastOperation(HAL_MAX_DELAY); + + FLASH->NSCR |= FLASH_NSCR_OBL_LAUNCH; // begin committing changes to flash + result = + flash_wait_and_clear_status_flags(); // wait until changes are committed + flash_lock_option_bytes(); + + if (flash_lock_write() != sectrue) { + return 0; + } + return result; +} + +void check_oem_keys(void) { + ensure(((FLASH_S->NSSR & FLASH_NSSR_OEM1LOCK) == 0) * sectrue, + "OEM1 KEY SET"); + ensure(((FLASH_S->NSSR & FLASH_NSSR_OEM2LOCK) == 0) * sectrue, + "OEM2 KEY SET"); +} + +secbool flash_configure_option_bytes(void) { + if (sectrue == flash_check_option_bytes()) { + return sectrue; // we DID NOT have to change the option bytes + } + + do { + flash_set_option_bytes(); + } while (sectrue != flash_check_option_bytes()); + + check_oem_keys(); + + return secfalse; // notify that we DID have to change the option bytes +} + +secbool flash_check_sec_area_ob(void) { + flash_wait_and_clear_status_flags(); + // check values stored in flash interface registers + + if (FLASH->SECWM1R1 != FLASH_SECWM1R1_VALUE) { + return secfalse; + } + if (FLASH->SECWM1R2 != FLASH_SECWM1R2_VALUE) { + return secfalse; + } + if (FLASH->SECWM2R1 != FLASH_SECWM2R1_VALUE) { + return secfalse; + } + if (FLASH->SECWM2R2 != FLASH_SECWM2R2_VALUE) { + return secfalse; + } + + return sectrue; +} + +uint32_t flash_set_sec_area_ob(void) { + if (flash_unlock_write() != sectrue) { + return 0; + } + flash_wait_and_clear_status_flags(); + flash_unlock_option_bytes(); + flash_wait_and_clear_status_flags(); + + FLASH->SECWM1R1 = FLASH_SECWM1R1_VALUE; + FLASH->SECWM1R2 = FLASH_SECWM1R2_VALUE; + + FLASH->SECWM2R1 = FLASH_SECWM2R1_VALUE; + FLASH->SECWM2R2 = FLASH_SECWM2R2_VALUE; + + FLASH_WaitForLastOperation(HAL_MAX_DELAY); + + FLASH->NSCR |= FLASH_NSCR_OPTSTRT; + uint32_t result = + flash_wait_and_clear_status_flags(); // wait until changes are committed + + FLASH_WaitForLastOperation(HAL_MAX_DELAY); + + FLASH->NSCR |= FLASH_NSCR_OBL_LAUNCH; // begin committing changes to flash + result = + flash_wait_and_clear_status_flags(); // wait until changes are committed + flash_lock_option_bytes(); + + if (flash_lock_write() != sectrue) { + return 0; + } + return result; +} + +secbool flash_configure_sec_area_ob(void) { + if (sectrue == flash_check_sec_area_ob()) { + return sectrue; // we DID NOT have to change the option bytes + } + + do { + flash_set_sec_area_ob(); + } while (sectrue != flash_check_sec_area_ob()); + + check_oem_keys(); + + return secfalse; // notify that we DID have to change the option bytes +} + +void periph_init(void) { + // STM32U5xx HAL library initialization: + // - configure the Flash prefetch, instruction and data caches + // - configure the Systick to generate an interrupt each 1 msec + // - set NVIC Group Priority to 4 + // - global MSP (MCU Support Package) initialization + HAL_Init(); + + // Enable GPIO clocks + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + +#ifdef USE_PVD + // enable the PVD (programmable voltage detector). + // select the "2.8V" threshold (level 5). + // this detector will be active regardless of the + // flash option byte BOR setting. + __HAL_RCC_PWR_CLK_ENABLE(); + PWR_PVDTypeDef pvd_config; + pvd_config.PVDLevel = PWR_PVDLEVEL_5; + pvd_config.Mode = PWR_PVD_MODE_IT_RISING_FALLING; + HAL_PWR_ConfigPVD(&pvd_config); + HAL_PWR_EnablePVD(); + NVIC_EnableIRQ(PVD_PVM_IRQn); +#endif +} + +secbool reset_flags_check(void) { +#if PRODUCTION + // this is effective enough that it makes development painful, so only use it + // for production. check the reset flags to assure that we arrive here due to + // a regular full power-on event, and not as a result of a lesser reset. + if ((RCC->CSR & (RCC_CSR_LPWRRSTF | RCC_CSR_WWDGRSTF | RCC_CSR_IWDGRSTF | + RCC_CSR_SFTRSTF | RCC_CSR_PINRSTF | RCC_CSR_BORRSTF | + RCC_CSR_OBLRSTF)) != (RCC_CSR_PINRSTF | RCC_CSR_BORRSTF)) { + return secfalse; + } +#endif + return sectrue; +} + +void reset_flags_reset(void) { + RCC->CSR |= RCC_CSR_RMVF; // clear the reset flags +} diff --git a/core/embed/trezorhal/stm32u5/mpu.c b/core/embed/trezorhal/stm32u5/mpu.c new file mode 100644 index 00000000000..8829c3e13f0 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/mpu.c @@ -0,0 +1,255 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include STM32_HAL_H +#include +#include "common.h" +#include "model.h" +#include "stm32u5xx_ll_cortex.h" + +// region type +#define MPUX_TYPE_FLASH_CODE 0 +#define MPUX_TYPE_SRAM 1 +#define MPUX_TYPE_PERIPHERAL 2 +#define MPUX_TYPE_FLASH_DATA 3 + +const static struct { + uint32_t xn; // executable + uint32_t attr; // attribute index + uint32_t sh; // shareable +} mpu_region_lookup[] = { + + // 0 - FLASH_CODE + { + .xn = LL_MPU_INSTRUCTION_ACCESS_ENABLE, + .attr = LL_MPU_ATTRIBUTES_NUMBER0, + .sh = LL_MPU_ACCESS_NOT_SHAREABLE, + }, + // 1 - SRAM + { + .xn = LL_MPU_INSTRUCTION_ACCESS_DISABLE, + .attr = LL_MPU_ATTRIBUTES_NUMBER1, + .sh = LL_MPU_ACCESS_INNER_SHAREABLE, + }, + // 2 - PERIPHERAL + { + .xn = LL_MPU_INSTRUCTION_ACCESS_DISABLE, + .attr = LL_MPU_ATTRIBUTES_NUMBER2, + .sh = LL_MPU_ACCESS_NOT_SHAREABLE, + }, + // 3 - FLASH_DATA + { + .xn = LL_MPU_INSTRUCTION_ACCESS_DISABLE, + .attr = LL_MPU_ATTRIBUTES_NUMBER3, + .sh = LL_MPU_ACCESS_NOT_SHAREABLE, + }, +}; + +static inline uint32_t mpu_permission_lookup(bool write, bool unpriv) { + if (write) { + return unpriv ? LL_MPU_REGION_ALL_RW : LL_MPU_REGION_PRIV_RW; + } else { + return unpriv ? LL_MPU_REGION_ALL_RO : LL_MPU_REGION_PRIV_RO; + } +} + +#define MPUX_FLAG_NO 0 +#define MPUX_FLAG_YES 1 + +#define SET_REGION(region, start, size, type, write, unpriv) \ + do { \ + uint32_t _type = MPUX_TYPE_##type; \ + uint32_t _write = MPUX_FLAG_##write; \ + uint32_t _unpriv = MPUX_FLAG_##unpriv; \ + MPU->RNR = LL_MPU_REGION_NUMBER##region; \ + uint32_t _start = (start) & (~0x1F); \ + uint32_t _sh = mpu_region_lookup[_type].sh; \ + uint32_t _ap = mpu_permission_lookup(_write, _unpriv); \ + uint32_t _xn = mpu_region_lookup[_type].xn; \ + MPU->RBAR = _start | _sh | _ap | _xn; \ + uint32_t _limit = (_start + (size)-1) & (~0x1F); \ + uint32_t _attr = mpu_region_lookup[_type].attr << 1; \ + uint32_t _enable = LL_MPU_REGION_ENABLE; \ + MPU->RLAR = _limit | _attr | _enable; \ + } while (0) + +#define DIS_REGION(region) \ + do { \ + MPU->RNR = LL_MPU_REGION_NUMBER##region; \ + MPU->RBAR = 0; \ + MPU->RLAR = 0; \ + } while (0) + +static void mpu_set_attributes(void) { + // Attr[0] - FLASH - Not-Transient, Write-Through, Read Allocation + MPU->MAIR0 = 0xAA; + // Attr[1] - SRAM - Non-cacheable + MPU->MAIR0 |= 0x44 << 8; + // Attr[2] - Peripherals - nGnRnE + MPU->MAIR0 |= 0x00 << 16; + // Attr[3] - FLASH - Non-cacheable + MPU->MAIR0 |= 0x44 << 24; +} + +#define SECRET_START FLASH_BASE +#define SECRET_SIZE SIZE_16K +#define BOARDLOADER_SIZE SIZE_48K +#define BOOTLOADER_SIZE BOOTLOADER_IMAGE_MAXSIZE +#define FIRMWARE_SIZE FIRMWARE_IMAGE_MAXSIZE +#define STORAGE_START \ + (FLASH_BASE + SECRET_SIZE + BOARDLOADER_SIZE + BOOTLOADER_SIZE) +#define STORAGE_SIZE NORCOW_SECTOR_SIZE* STORAGE_AREAS_COUNT + +#if defined STM32U5A9xx +#define SRAM_SIZE SIZE_2496K +#elif defined STM32U5G9xx +#define SRAM_SIZE (SIZE_2496K + SIZE_512K) +#elif defined STM32U585xx +#define SRAM_SIZE SIZE_768K +#else +#error "Unknown MCU" +#endif + +#define L1_REST_SIZE (FLASH_SIZE - (BOARDLOADER_SIZE + SECRET_SIZE)) + +#define L2_PREV_SIZE (SECRET_SIZE + BOARDLOADER_SIZE) +#define L2_REST_SIZE \ + (FLASH_SIZE - (BOOTLOADER_SIZE + BOARDLOADER_SIZE + SECRET_SIZE)) + +#define L3_PREV_SIZE \ + (STORAGE_SIZE + BOOTLOADER_SIZE + BOARDLOADER_SIZE + SECRET_SIZE) + +#define ASSETS_START (FIRMWARE_START + FIRMWARE_SIZE) +#define ASSETS_SIZE \ + (FLASH_SIZE - (FIRMWARE_SIZE + BOOTLOADER_SIZE + BOARDLOADER_SIZE + \ + SECRET_SIZE + STORAGE_SIZE)) + +#define L3_PREV_SIZE_BLD (STORAGE_SIZE + BOOTLOADER_SIZE) + +#ifdef STM32U585xx +#define GRAPHICS_START FMC_BANK1 +#define GRAPHICS_SIZE SIZE_16M +#else +#define GRAPHICS_START GFXMMU_VIRTUAL_BUFFERS_BASE +#define GRAPHICS_SIZE SIZE_16M +#endif + +void mpu_config_boardloader(void) { + HAL_MPU_Disable(); + mpu_set_attributes(); + // clang-format off + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, SECRET_START, SECRET_SIZE, FLASH_DATA, YES, NO ); // Secret + SET_REGION( 1, BOARDLOADER_START, BOARDLOADER_SIZE, FLASH_CODE, NO, NO ); // Boardloader code + SET_REGION( 2, BOOTLOADER_START, L1_REST_SIZE, FLASH_DATA, YES, NO ); // Bootloader + Storage + Firmware + SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); // SRAM1/2/3/5 + SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); // Frame buffer or display interface + SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); // Peripherals + DIS_REGION( 6 ); + SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, NO ); // SRAM4 + // clang-format on + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_bootloader(void) { + HAL_MPU_Disable(); + mpu_set_attributes(); + // clang-format off + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, SECRET_START, L2_PREV_SIZE, FLASH_DATA, YES, NO ); // Secret + Boardloader + SET_REGION( 1, BOOTLOADER_START, BOOTLOADER_SIZE, FLASH_CODE, NO, NO ); // Bootloader code + SET_REGION( 2, STORAGE_START, L2_REST_SIZE, FLASH_DATA, YES, NO ); // Storage + Firmware + SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, NO ); // SRAM1/2/3/5 + SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, NO ); // Frame buffer or display interface + SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, NO ); // Peripherals + SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, NO ); // OTP + SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, NO ); // SRAM4 + // clang-format on + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_firmware_initial(void) { + HAL_MPU_Disable(); + mpu_set_attributes(); + // clang-format off + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, BOOTLOADER_START, L3_PREV_SIZE_BLD, FLASH_DATA, YES, YES ); // Bootloader + Storage + SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware + SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets + SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 + SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface + SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals + SET_REGION( 6, FLASH_OTP_BASE, SIZE_2K, FLASH_DATA, YES, YES ); // OTP + SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + // clang-format on + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_firmware(void) { + HAL_MPU_Disable(); + mpu_set_attributes(); + // clang-format off + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, YES ); // Storage + SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware + SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets + SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 + SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface + SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals + SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, YES ); // OTP + SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + // clang-format on + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_prodtest_initial(void) { + HAL_MPU_Disable(); + mpu_set_attributes(); + // clang-format off + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, FLASH_BASE, L3_PREV_SIZE, FLASH_DATA, YES, YES ); // Secret, Bld, Storage + SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware + SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets + SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 + SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface + SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals + SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, YES ); // OTP + SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + // clang-format on + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_prodtest(void) { + HAL_MPU_Disable(); + mpu_set_attributes(); + // clang-format off + // REGION ADDRESS SIZE TYPE WRITE UNPRIV + SET_REGION( 0, STORAGE_START, STORAGE_SIZE, FLASH_DATA, YES, YES ); // Storage + SET_REGION( 1, FIRMWARE_START, FIRMWARE_SIZE, FLASH_CODE, NO, YES ); // Firmware + SET_REGION( 2, ASSETS_START, ASSETS_SIZE, FLASH_DATA, YES, YES ); // Assets + SET_REGION( 3, SRAM1_BASE, SRAM_SIZE, SRAM, YES, YES ); // SRAM1/2/3/5 + SET_REGION( 4, GRAPHICS_START, GRAPHICS_SIZE, SRAM, YES, YES ); // Frame buffer or display interface + SET_REGION( 5, PERIPH_BASE_NS, SIZE_512M, PERIPHERAL, YES, YES ); // Peripherals + SET_REGION( 6, FLASH_OTP_BASE, FLASH_OTP_SIZE, FLASH_DATA, YES, YES ); // OTP + SET_REGION( 7, SRAM4_BASE, SIZE_16K, SRAM, YES, YES ); // SRAM4 + // clang-format on + HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI); +} + +void mpu_config_off(void) { HAL_MPU_Disable(); } diff --git a/core/embed/trezorhal/stm32u5/optiga_hal.c b/core/embed/trezorhal/stm32u5/optiga_hal.c new file mode 120000 index 00000000000..bd07df70445 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/optiga_hal.c @@ -0,0 +1 @@ +../stm32f4/optiga_hal.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/platform.c b/core/embed/trezorhal/stm32u5/platform.c new file mode 100644 index 00000000000..fb6657a029d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/platform.c @@ -0,0 +1,214 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include STM32_HAL_H + +#include "platform.h" +#include "rng.h" +#include TREZOR_BOARD + +const uint8_t AHBPrescTable[16] = {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, + 1U, 2U, 3U, 4U, 6U, 7U, 8U, 9U}; +const uint8_t APBPrescTable[8] = {0U, 0U, 0U, 0U, 1U, 2U, 3U, 4U}; +const uint32_t MSIRangeTable[16] = {48000000U, 24000000U, 16000000U, 12000000U, + 4000000U, 2000000U, 1330000U, 1000000U, + 3072000U, 1536000U, 1024000U, 768000U, + 400000U, 200000U, 133000U, 100000U}; +typedef struct { + uint32_t freq; + uint32_t pllq; + uint32_t pllp; + uint32_t pllm; + uint32_t plln; +} clock_conf_t; + +#if defined STM32U5 +#define DEFAULT_FREQ 160U +#define DEFAULT_PLLM 1 +#define DEFAULT_PLLN (10 * PLLN_COEF) // mult by 10 +#define DEFAULT_PLLR 1U // division by 1 +#define DEFAULT_PLLQ 1U // division by 1 +#define DEFAULT_PLLP 5U // division by 5 +#else +#error Unsupported MCU +#endif + +uint32_t SystemCoreClock = DEFAULT_FREQ * 1000000U; + +// PLLCLK = ((HSE / PLLM) * PLLN) / PLLR +#ifdef HSE_16MHZ +#define PLLN_COEF 1U +#elif defined HSE_8MHZ +#define PLLN_COEF 2U +#else +#error Unsupported HSE frequency +#endif + +// assuming HSE 16 MHz +clock_conf_t clock_conf[1] = { + { + // clk = ((16MHz / 1) * 10) / 1 = 160 MHz + .freq = 160, + .pllp = 1, + .pllq = 1, + .pllm = 1, + .plln = 10 * PLLN_COEF, + }, +}; + +#pragma GCC optimize( \ + "no-stack-protector") // applies to all functions in this file + +void SystemInit(void) { + // set flash wait states for an increasing HCLK frequency + + FLASH->ACR = FLASH_ACR_LATENCY_5WS; + // wait until the new wait state config takes effect -- per section 3.5.1 + // guidance + while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_5WS) + ; + + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set MSION bit */ + RCC->CR = RCC_CR_MSISON; + + /* Reset CFGR register */ + RCC->CFGR1 = 0U; + RCC->CFGR2 = 0U; + RCC->CFGR3 = 0U; + + /* Reset HSEON, CSSON , HSION, PLLxON bits */ + RCC->CR &= ~(RCC_CR_HSEON | RCC_CR_CSSON | RCC_CR_PLL1ON | RCC_CR_PLL2ON | + RCC_CR_PLL3ON | RCC_CR_HSI48ON); + + /* Reset PLLCFGR register */ + RCC->PLL1CFGR = 0U; + + /* Reset HSEBYP bit */ + RCC->CR &= ~(RCC_CR_HSEBYP); + + /* Disable all interrupts */ + RCC->CIER = 0U; + + __HAL_RCC_PWR_CLK_ENABLE(); + + MODIFY_REG(PWR->VOSR, (PWR_VOSR_VOS | PWR_VOSR_BOOSTEN), + PWR_REGULATOR_VOLTAGE_SCALE1); + while (HAL_IS_BIT_CLR(PWR->VOSR, PWR_VOSR_VOSRDY)) + ; + while (HAL_IS_BIT_CLR(PWR->SVMSR, PWR_SVMSR_ACTVOSRDY)) + ; + + __HAL_RCC_HSE_CONFIG(RCC_HSE_ON); + while (READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) + ; + + __HAL_RCC_PLL_CONFIG(RCC_PLLSOURCE_HSE, RCC_PLLMBOOST_DIV1, DEFAULT_PLLM, + DEFAULT_PLLN, DEFAULT_PLLP, DEFAULT_PLLQ, DEFAULT_PLLR); + + __HAL_RCC_PLL_FRACN_DISABLE(); + + __HAL_RCC_PLL_VCIRANGE(RCC_PLLVCIRANGE_1); + + __HAL_RCC_PLLCLKOUT_ENABLE(RCC_PLL1_DIVR); + + __HAL_RCC_PLL_ENABLE(); + while (READ_BIT(RCC->CR, RCC_CR_PLL1RDY) == 0U) + ; + + __HAL_RCC_HSI48_ENABLE(); + while (READ_BIT(RCC->CR, RCC_CR_HSI48RDY) == 0U) + ; + + /** Initializes the CPU, AHB and APB buses clocks + */ + FLASH->ACR = FLASH_ACR_LATENCY_4WS; + // wait until the new wait state config takes effect -- per section 3.5.1 + // guidance + while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_4WS) + ; + MODIFY_REG(RCC->CFGR3, RCC_CFGR3_PPRE3, RCC_HCLK_DIV1); + MODIFY_REG(RCC->CFGR2, RCC_CFGR2_PPRE2, ((RCC_HCLK_DIV1) << 4)); + MODIFY_REG(RCC->CFGR2, RCC_CFGR2_PPRE1, RCC_HCLK_DIV1); + MODIFY_REG(RCC->CFGR2, RCC_CFGR2_HPRE, RCC_SYSCLK_DIV1); + + MODIFY_REG(RCC->CFGR1, RCC_CFGR1_SW, RCC_SYSCLKSOURCE_PLLCLK); + + /* + * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral + */ + HAL_PWREx_DisableUCPDDeadBattery(); + +#ifdef USE_SMPS + /* + * Switch to SMPS regulator instead of LDO + */ + SET_BIT(PWR->CR3, PWR_CR3_REGSEL); + /* Wait until system switch on new regulator */ + while (HAL_IS_BIT_CLR(PWR->SVMSR, PWR_SVMSR_REGS)) + ; +#endif + + __HAL_RCC_PWR_CLK_DISABLE(); + + // this will be overriden by static initialization + SystemCoreClock = DEFAULT_FREQ * 1000000U; + + // enable clock security system, HSE clock, and main PLL + RCC->CR |= RCC_CR_CSSON; + + // turn off the HSI as it is now unused (it will be turned on again + // automatically if a clock security failure occurs) + RCC->CR &= ~RCC_CR_HSION; + // wait until ths HSI is off + while ((RCC->CR & RCC_CR_HSION) == RCC_CR_HSION) + ; + + // TODO turn off MSI? + + // init the TRNG peripheral + rng_init(); + + // set CP10 and CP11 to enable full access to the fpu coprocessor; + SCB->CPACR |= + ((3UL << 20U) | (3UL << 22U)); /* set CP10 and CP11 Full Access */ + +#if defined(__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U) + SCB_NS->CPACR |= + ((3UL << 20U) | (3UL << 22U)); /* set CP10 and CP11 Full Access */ +#endif + + // enable instruction cache in default 2-way mode + ICACHE->CR = ICACHE_CR_EN; +} + +void drop_privileges(void) { + // jump to unprivileged mode + // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html + __asm__ volatile("msr control, %0" ::"r"(0x1)); + __asm__ volatile("isb"); +} + +// from util.s +extern void shutdown_privileged(void); + +void PVD_PVM_IRQHandler(void) { + TIM1->CCR1 = 0; // turn off display backlight + shutdown_privileged(); +} diff --git a/core/embed/trezorhal/stm32u5/platform.h b/core/embed/trezorhal/stm32u5/platform.h new file mode 100644 index 00000000000..233a367dd86 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/platform.h @@ -0,0 +1,56 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#ifndef TREZORHAL_STM32_H +#define TREZORHAL_STM32_H + +#include STM32_HAL_H +#include + +#define SENSITIVE __attribute__((section(".sensitive"))) + +typedef enum { + CLOCK_160_MHZ = 0, +} clock_settings_t; + +void set_core_clock(clock_settings_t settings); +void ensure_compatible_settings(void); +void drop_privileges(void); + +// the following functions are defined in util.s +void memset_reg(volatile void *start, volatile void *stop, uint32_t val); +void jump_to(uint32_t address); +void jump_to_unprivileged(uint32_t address); +void jump_to_with_flag(uint32_t address, uint32_t register_flag); + +extern uint32_t __stack_chk_guard; + +// this deletes all secrets and SRAM2 where stack is located +// to prevent stack smashing error, do not return from function calling this +static inline void __attribute__((always_inline)) delete_secrets(void) { + // Disable SAES peripheral clock, so that we don't get tamper events + __HAL_RCC_SAES_CLK_DISABLE(); + + // Erase all + TAMP->CR2 |= TAMP_CR2_BKERASE; +} + +void check_oem_keys(void); + +#endif // TREZORHAL_STM32_H diff --git a/core/embed/trezorhal/stm32u5/random_delays.c b/core/embed/trezorhal/stm32u5/random_delays.c new file mode 120000 index 00000000000..eb47d772938 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/random_delays.c @@ -0,0 +1 @@ +../stm32f4/random_delays.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/rng.c b/core/embed/trezorhal/stm32u5/rng.c new file mode 120000 index 00000000000..f16159d7875 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/rng.c @@ -0,0 +1 @@ +../stm32f4/rng.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/sbu.c b/core/embed/trezorhal/stm32u5/sbu.c new file mode 120000 index 00000000000..54c434947dc --- /dev/null +++ b/core/embed/trezorhal/stm32u5/sbu.c @@ -0,0 +1 @@ +../stm32f4/sbu.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/sdcard.c b/core/embed/trezorhal/stm32u5/sdcard.c new file mode 100644 index 00000000000..3d7aee67a05 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/sdcard.c @@ -0,0 +1,340 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include STM32_HAL_H +#include TREZOR_BOARD + +#include + +#include "irq.h" +#include "sdcard.h" +#include "supervise.h" + +#define SDMMC_CLK_ENABLE() __HAL_RCC_SDMMC1_CLK_ENABLE() +#define SDMMC_CLK_DISABLE() __HAL_RCC_SDMMC1_CLK_DISABLE() +#define SDMMC_IRQn SDMMC1_IRQn + +static SD_HandleTypeDef sd_handle = {0}; + +// this function is inspired by functions in stm32f4xx_ll_sdmmc.c +uint32_t SDMMC_CmdSetClrCardDetect(SDMMC_TypeDef *SDMMCx, uint32_t Argument) { + SDMMC_CmdInitTypeDef sdmmc_cmdinit; + uint32_t errorstate = SDMMC_ERROR_NONE; + + sdmmc_cmdinit.Argument = (uint32_t)Argument; + sdmmc_cmdinit.CmdIndex = SDMMC_CMD_SD_APP_SET_CLR_CARD_DETECT; + sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; + sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; + sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; + SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); + + errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SD_APP_SET_CLR_CARD_DETECT, + SDMMC_CMDTIMEOUT); + + return errorstate; +} + +static inline void sdcard_default_pin_state(void) { + HAL_GPIO_WritePin(SD_ENABLE_PORT, SD_ENABLE_PIN, GPIO_PIN_SET); // SD_ON + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET); // SD_DAT0/PC8 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET); // SD_DAT1/PC9 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET); // SD_DAT2/PC10 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_11, GPIO_PIN_RESET); // SD_DAT3/PC11 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_12, GPIO_PIN_RESET); // SD_CLK/PC12 + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET); // SD_CMD/PD2 + + GPIO_InitTypeDef GPIO_InitStructure; + + // configure the SD card circuitry on/off pin + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = SD_ENABLE_PIN; + HAL_GPIO_Init(SD_ENABLE_PORT, &GPIO_InitStructure); + + // configure SD GPIO + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + + // configure the SD card detect pin + GPIO_InitStructure.Mode = GPIO_MODE_INPUT; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Pin = SD_DETECT_PIN; + HAL_GPIO_Init(SD_DETECT_PORT, &GPIO_InitStructure); +} + +static inline void sdcard_active_pin_state(void) { + HAL_GPIO_WritePin(SD_ENABLE_PORT, SD_ENABLE_PIN, GPIO_PIN_RESET); + HAL_Delay(10); // we need to wait until the circuit fully kicks-in + + GPIO_InitTypeDef GPIO_InitStructure; + + // configure SD GPIO + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = GPIO_AF12_SDMMC1; + GPIO_InitStructure.Pin = + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_InitStructure.Pin = GPIO_PIN_2; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); +} + +void sdcard_init(void) { sdcard_default_pin_state(); } + +void HAL_SD_MspInit(SD_HandleTypeDef *hsd) { + if (hsd->Instance == sd_handle.Instance) { + // enable SDIO clock + SDMMC_CLK_ENABLE(); + + // NVIC configuration for SDIO interrupts + svc_setpriority(SDMMC_IRQn, IRQ_PRI_SDIO); + svc_enableIRQ(SDMMC_IRQn); + } + + // GPIO have already been initialised by sdcard_init +} + +void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) { + if (hsd->Instance == sd_handle.Instance) { + svc_disableIRQ(SDMMC_IRQn); + SDMMC_CLK_DISABLE(); + } +} + +secbool sdcard_power_on(void) { + if (sectrue != sdcard_is_present()) { + return secfalse; + } + if (sd_handle.Instance) { + return sectrue; + } + // turn on SD card circuitry + sdcard_active_pin_state(); + HAL_Delay(50); + + // SD device interface configuration + sd_handle.Instance = SDMMC1; + sd_handle.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + sd_handle.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE; + sd_handle.Init.BusWide = SDMMC_BUS_WIDE_1B; + sd_handle.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + sd_handle.Init.ClockDiv = 0; + + // init the SD interface, with retry if it's not ready yet + for (int retry = 10; HAL_SD_Init(&sd_handle) != HAL_OK; retry--) { + if (retry == 0) { + goto error; + } + HAL_Delay(50); + } + + // disable the card's internal CD/DAT3 card detect pull-up resistor + // to send ACMD42, we have to send CMD55 (APP_CMD) with the card's RCA as + // the argument followed by CMD42 (SET_CLR_CARD_DETECT) + if (SDMMC_CmdAppCommand(sd_handle.Instance, sd_handle.SdCard.RelCardAdd + << 16U) != SDMMC_ERROR_NONE) { + goto error; + } + if (SDMMC_CmdSetClrCardDetect(sd_handle.Instance, 0) != SDMMC_ERROR_NONE) { + goto error; + } + + // configure the SD bus width for wide operation + if (HAL_SD_ConfigWideBusOperation(&sd_handle, SDMMC_BUS_WIDE_4B) != HAL_OK) { + HAL_SD_DeInit(&sd_handle); + goto error; + } + + return sectrue; + +error: + sdcard_power_off(); + return secfalse; +} + +void sdcard_power_off(void) { + if (sd_handle.Instance) { + HAL_SD_DeInit(&sd_handle); + sd_handle.Instance = NULL; + } + // turn off SD card circuitry + HAL_Delay(50); + sdcard_default_pin_state(); + HAL_Delay(100); +} + +secbool sdcard_is_present(void) { + return sectrue * + (GPIO_PIN_RESET == HAL_GPIO_ReadPin(SD_DETECT_PORT, SD_DETECT_PIN)); +} + +uint64_t sdcard_get_capacity_in_bytes(void) { + if (sd_handle.Instance == NULL) { + return 0; + } + HAL_SD_CardInfoTypeDef cardinfo; + HAL_SD_GetCardInfo(&sd_handle, &cardinfo); + return (uint64_t)cardinfo.LogBlockNbr * (uint64_t)cardinfo.LogBlockSize; +} + +void SDMMC1_IRQHandler(void) { + IRQ_ENTER(SDIO_IRQn); + if (sd_handle.Instance) { + HAL_SD_IRQHandler(&sd_handle); + } + IRQ_EXIT(SDIO_IRQn); +} + +static void sdcard_reset_periph(void) { + // Fully reset the SDMMC peripheral before calling HAL SD DMA functions. + // (There could be an outstanding DTIMEOUT event from a previous call and the + // HAL function enables IRQs before fully configuring the SDMMC peripheral.) + SDMMC1->DTIMER = 0; + SDMMC1->DLEN = 0; + SDMMC1->DCTRL = 0; + SDMMC1->ICR = SDMMC_STATIC_FLAGS; +} + +static HAL_StatusTypeDef sdcard_wait_finished(SD_HandleTypeDef *sd, + uint32_t timeout) { + // Wait for HAL driver to be ready (eg for DMA to finish) + uint32_t start = HAL_GetTick(); + for (;;) { + // Do an atomic check of the state; WFI will exit even if IRQs are disabled + uint32_t irq_state = disable_irq(); + if (sd->State != HAL_SD_STATE_BUSY) { + enable_irq(irq_state); + break; + } + __WFI(); + enable_irq(irq_state); + if (HAL_GetTick() - start >= timeout) { + return HAL_TIMEOUT; + } + } + + // Wait for SD card to complete the operation + for (;;) { + HAL_SD_CardStateTypeDef state = HAL_SD_GetCardState(sd); + if (state == HAL_SD_CARD_TRANSFER) { + return HAL_OK; + } + if (!(state == HAL_SD_CARD_SENDING || state == HAL_SD_CARD_RECEIVING || + state == HAL_SD_CARD_PROGRAMMING)) { + return HAL_ERROR; + } + if (HAL_GetTick() - start >= timeout) { + return HAL_TIMEOUT; + } + __WFI(); + } + return HAL_OK; +} + +secbool sdcard_read_blocks(uint32_t *dest, uint32_t block_num, + uint32_t num_blocks) { + // check that SD card is initialised + if (sd_handle.Instance == NULL) { + return secfalse; + } + + // check that dest pointer is aligned on a 4-byte boundary + if (((uint32_t)dest & 3) != 0) { + return secfalse; + } + + HAL_StatusTypeDef err = HAL_OK; + + // we must disable USB irqs to prevent MSC contention with SD card + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + sdcard_reset_periph(); + err = + HAL_SD_ReadBlocks_DMA(&sd_handle, (uint8_t *)dest, block_num, num_blocks); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 5000); + } + restore_irq_pri(basepri); + + return sectrue * (err == HAL_OK); +} + +secbool sdcard_write_blocks(const uint32_t *src, uint32_t block_num, + uint32_t num_blocks) { + // check that SD card is initialised + if (sd_handle.Instance == NULL) { + return secfalse; + } + + // check that src pointer is aligned on a 4-byte boundary + if (((uint32_t)src & 3) != 0) { + return secfalse; + } + + HAL_StatusTypeDef err = HAL_OK; + + // we must disable USB irqs to prevent MSC contention with SD card + uint32_t basepri = raise_irq_pri(IRQ_PRI_OTG_FS); + + sdcard_reset_periph(); + err = + HAL_SD_WriteBlocks_DMA(&sd_handle, (uint8_t *)src, block_num, num_blocks); + if (err == HAL_OK) { + err = sdcard_wait_finished(&sd_handle, 5000); + } + + restore_irq_pri(basepri); + + return sectrue * (err == HAL_OK); +} diff --git a/core/embed/trezorhal/stm32u5/secret.c b/core/embed/trezorhal/stm32u5/secret.c new file mode 100644 index 00000000000..7fd3c08e961 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/secret.c @@ -0,0 +1,166 @@ +#include "secret.h" +#include +#include +#include "common.h" +#include "flash.h" +#include "model.h" +#include "rng.h" + +static secbool bootloader_locked_set = secfalse; +static secbool bootloader_locked = secfalse; + +static secbool verify_header(void) { + uint8_t header[SECRET_HEADER_LEN] = {0}; + + memcpy(header, flash_area_get_address(&SECRET_AREA, 0, SECRET_HEADER_LEN), + SECRET_HEADER_LEN); + + bootloader_locked = + memcmp(header, SECRET_HEADER_MAGIC, 4) == 0 ? sectrue : secfalse; + bootloader_locked_set = sectrue; + return bootloader_locked; +} + +secbool secret_bootloader_locked(void) { +#ifdef FIRMWARE + return TAMP->BKP8R != 0 * sectrue; +#else + return sectrue; +#endif +} + +void secret_write_header(void) { + uint8_t header[SECRET_HEADER_LEN] = {0}; + memcpy(header, SECRET_HEADER_MAGIC, 4); + secret_write(header, 0, SECRET_HEADER_LEN); +} + +void secret_write(uint8_t *data, uint32_t offset, uint32_t len) { + ensure(flash_unlock_write(), "secret write"); + for (int i = 0; i < len / 16; i++) { + ensure(flash_area_write_quadword(&SECRET_AREA, offset + (i * 16), + (uint32_t *)&data[(i * 16)]), + "secret write"); + } + ensure(flash_lock_write(), "secret write"); +} + +secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) { + if (sectrue != verify_header()) { + return secfalse; + } + + memcpy(data, flash_area_get_address(&SECRET_AREA, offset, len), len); + + return sectrue; +} + +void secret_hide(void) { + FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP1_ACCDIS_Msk; + FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP2_ACCDIS_Msk; +} + +void secret_bhk_lock(void) { + TAMP_S->SECCFGR = 8 << TAMP_SECCFGR_BKPRWSEC_Pos | TAMP_SECCFGR_BHKLOCK; +} + +secbool secret_bhk_locked(void) { + return ((TAMP_S->SECCFGR & TAMP_SECCFGR_BHKLOCK) == TAMP_SECCFGR_BHKLOCK) * + sectrue; +} + +void secret_bhk_provision(void) { + uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0}; + secbool ok = + secret_read((uint8_t *)secret, SECRET_BHK_OFFSET, SECRET_BHK_LEN); + + volatile uint32_t *reg1 = &TAMP->BKP0R; + if (sectrue == ok) { + for (int i = 0; i < 8; i++) { + *reg1 = ((uint32_t *)secret)[i]; + reg1++; + } + } else { + for (int i = 0; i < 8; i++) { + *reg1 = 0; + reg1++; + } + } +} + +void secret_bhk_regenerate(void) { + ensure(flash_area_erase(&BHK_AREA, NULL), "Failed regenerating BHK"); + ensure(flash_unlock_write(), "Failed regenerating BHK"); + for (int i = 0; i < 2; i++) { + uint32_t val[4] = {0}; + for (int j = 0; j < 4; j++) { + val[j] = rng_get(); + } + ensure(flash_area_write_quadword(&BHK_AREA, i * 4 * sizeof(uint32_t), val), + "Failed regenerating BHK"); + } + ensure(flash_lock_write(), "Failed regenerating BHK"); +} + +secbool secret_optiga_present(void) { + uint8_t *optiga_secret = (uint8_t *)flash_area_get_address( + &SECRET_AREA, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); + + int optiga_secret_empty_bytes = 0; + + for (int i = 0; i < SECRET_OPTIGA_KEY_LEN; i++) { + if (optiga_secret[i] == 0xFF) { + optiga_secret_empty_bytes++; + } + } + return sectrue * (optiga_secret_empty_bytes != SECRET_OPTIGA_KEY_LEN); +} + +void secret_optiga_backup(void) { + uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0}; + secbool ok = secret_read((uint8_t *)secret, SECRET_OPTIGA_KEY_OFFSET, + SECRET_OPTIGA_KEY_LEN); + + volatile uint32_t *reg1 = &TAMP->BKP8R; + if (sectrue == ok) { + for (int i = 0; i < 8; i++) { + *reg1 = ((uint32_t *)secret)[i]; + reg1++; + } + } else { + for (int i = 0; i < 8; i++) { + *reg1 = 0; + reg1++; + } + } +} + +secbool secret_optiga_extract(uint8_t *dest) { + bool all_zero = true; + volatile uint32_t *reg1 = &TAMP->BKP8R; + for (int i = 0; i < 8; i++) { + uint32_t val = *reg1++; + + if (val != 0) { + all_zero = false; + } + + for (int j = 0; j < 4; j++) { + dest[i * 4 + j] = (val >> (j * 8)) & 0xFF; + } + } + + return all_zero ? secfalse : sectrue; +} + +void secret_optiga_hide(void) { + volatile uint32_t *reg1 = &TAMP->BKP8R; + for (int i = 0; i < 8; i++) { + *reg1 = 0; + reg1++; + } +} + +void secret_erase(void) { + ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); +} diff --git a/core/embed/trezorhal/stm32u5/secure_aes.c b/core/embed/trezorhal/stm32u5/secure_aes.c new file mode 100644 index 00000000000..9fd964e67cc --- /dev/null +++ b/core/embed/trezorhal/stm32u5/secure_aes.c @@ -0,0 +1,117 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include +#include STM32_HAL_H + +#include +#include + +secbool secure_aes_init(void) { + RCC_OscInitTypeDef osc_init_def = {0}; + osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_SHSI; + osc_init_def.SHSIState = RCC_SHSI_ON; + + // Enable SHSI clock + if (HAL_RCC_OscConfig(&osc_init_def) != HAL_OK) { + return secfalse; + } + + // Enable SAES peripheral clock + __HAL_RCC_SAES_CLK_ENABLE(); + + return sectrue; +} + +static void secure_aes_load_bhk(void) { + TAMP->BKP7R; + TAMP->BKP6R; + TAMP->BKP5R; + TAMP->BKP4R; + TAMP->BKP3R; + TAMP->BKP2R; + TAMP->BKP1R; + TAMP->BKP0R; +} + +secbool secure_aes_encrypt(uint32_t* input, size_t size, uint32_t* output) { + CRYP_HandleTypeDef hcryp = {0}; + uint32_t iv[] = {0, 0, 0, 0}; + + hcryp.Instance = SAES; + hcryp.Init.DataType = CRYP_NO_SWAP; + hcryp.Init.KeySelect = CRYP_KEYSEL_HSW; + hcryp.Init.KeySize = CRYP_KEYSIZE_256B; + hcryp.Init.pKey = NULL; + hcryp.Init.pInitVect = iv; + hcryp.Init.Algorithm = CRYP_AES_ECB; + hcryp.Init.Header = NULL; + hcryp.Init.HeaderSize = 0; + hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_WORD; + hcryp.Init.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE; + hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL; + + if (HAL_CRYP_Init(&hcryp) != HAL_OK) { + return secfalse; + } + + secure_aes_load_bhk(); + + if (HAL_CRYP_Encrypt(&hcryp, input, size, output, HAL_MAX_DELAY) != HAL_OK) { + return secfalse; + } + + HAL_CRYP_DeInit(&hcryp); + + return sectrue; +} + +secbool secure_aes_decrypt(uint32_t* input, size_t size, uint32_t* output) { + CRYP_HandleTypeDef hcryp = {0}; + uint32_t iv[] = {0, 0, 0, 0}; + + hcryp.Instance = SAES; + hcryp.Init.DataType = CRYP_NO_SWAP; + hcryp.Init.KeySelect = CRYP_KEYSEL_HSW; + hcryp.Init.KeySize = CRYP_KEYSIZE_256B; + hcryp.Init.pKey = NULL; + hcryp.Init.pInitVect = iv; + hcryp.Init.Algorithm = CRYP_AES_ECB; + hcryp.Init.Header = NULL; + hcryp.Init.HeaderSize = 0; + hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; + hcryp.Init.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE; + hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ALWAYS; + hcryp.Init.KeyMode = CRYP_KEYMODE_NORMAL; + + if (HAL_CRYP_Init(&hcryp) != HAL_OK) { + return secfalse; + } + + secure_aes_load_bhk(); + + if (HAL_CRYP_Decrypt(&hcryp, input, size, output, HAL_MAX_DELAY) != HAL_OK) { + return secfalse; + } + + HAL_CRYP_DeInit(&hcryp); + + return sectrue; +} diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h new file mode 100644 index 00000000000..97c580fbb1b --- /dev/null +++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_conf.h @@ -0,0 +1,567 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file stm32u5xx_hal_conf.h + * @author MCD Application Team + * @brief HAL configuration file. + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef STM32U5xx_HAL_CONF_H +#define STM32U5xx_HAL_CONF_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ + +#ifdef STM32U585xx +#define USE_USB_FS +#else +#define USE_USB_HS +#define USE_USB_HS_INTERNAL_PHY +#endif + +/* ########################## Module Selection ############################## */ +/** + * @brief This is the list of modules to be used in the HAL driver + */ + +#define HAL_MODULE_ENABLED + +/*#define HAL_ADC_MODULE_ENABLED */ +/*#define HAL_MDF_MODULE_ENABLED */ +/*#define HAL_COMP_MODULE_ENABLED */ +/*#define HAL_CORDIC_MODULE_ENABLED */ +/*#define HAL_CRC_MODULE_ENABLED */ +/*#define HAL_CRYP_MODULE_ENABLED */ +/*#define HAL_DAC_MODULE_ENABLED */ +#define HAL_DMA2D_MODULE_ENABLED +#define HAL_DSI_MODULE_ENABLED +/*#define HAL_FDCAN_MODULE_ENABLED */ +/*#define HAL_FMAC_MODULE_ENABLED */ +#define HAL_GFXMMU_MODULE_ENABLED +/*#define HAL_GPU2D_MODULE_ENABLED */ +#define HAL_GTZC_MODULE_ENABLED +#define HAL_HASH_MODULE_ENABLED +/*#define HAL_HRTIM_MODULE_ENABLED */ +/*#define HAL_IRDA_MODULE_ENABLED */ +/*#define HAL_IWDG_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED +/*#define HAL_I2S_MODULE_ENABLED */ +/*#define HAL_LPTIM_MODULE_ENABLED */ +#define HAL_LTDC_MODULE_ENABLED +/*#define HAL_NAND_MODULE_ENABLED */ +/*#define HAL_NOR_MODULE_ENABLED */ +/*#define HAL_OPAMP_MODULE_ENABLED */ +/*#define HAL_OSPI_MODULE_ENABLED */ +/*#define HAL_OTFDEC_MODULE_ENABLED */ +/*#define HAL_PKA_MODULE_ENABLED */ +/*#define HAL_QSPI_MODULE_ENABLED */ +/*#define HAL_RNG_MODULE_ENABLED */ +#define HAL_RTC_MODULE_ENABLED +/*#define HAL_SAI_MODULE_ENABLED */ +#define HAL_CRYP_MODULE_ENABLED +#define HAL_SD_MODULE_ENABLED +/*#define HAL_MMC_MODULE_ENABLED */ +/*#define HAL_SMARTCARD_MODULE_ENABLED */ +/*#define HAL_SMBUS_MODULE_ENABLED */ +/*#define HAL_SPI_MODULE_ENABLED */ +#define HAL_SRAM_MODULE_ENABLED +#define HAL_TIM_MODULE_ENABLED +/*#define HAL_TSC_MODULE_ENABLED */ +/*#define HAL_RAMCFG_MODULE_ENABLED */ +#define HAL_UART_MODULE_ENABLED +/*#define HAL_USART_MODULE_ENABLED */ +/*#define HAL_WWDG_MODULE_ENABLED */ +/*#define HAL_DCMI_MODULE_ENABLED */ +/*#define HAL_PSSI_MODULE_ENABLED */ +#define HAL_ICACHE_MODULE_ENABLED +/*#define HAL_DCACHE_MODULE_ENABLED */ +#define HAL_PCD_MODULE_ENABLED +/*#define HAL_HCD_MODULE_ENABLED */ +/*#define HAL_XSPI_MODULE_ENABLED */ + +#define HAL_GPIO_MODULE_ENABLED +#define HAL_EXTI_MODULE_ENABLED +#define HAL_DMA_MODULE_ENABLED +#define HAL_RCC_MODULE_ENABLED +#define HAL_FLASH_MODULE_ENABLED +#define HAL_PWR_MODULE_ENABLED +#define HAL_CORTEX_MODULE_ENABLED + +/* ########################## Oscillator Values adaptation + * ####################*/ +/** + * @brief Adjust the value of External High Speed oscillator (HSE) used in your + * application. This value is used by the RCC HAL module to compute the system + * frequency (when HSE is used as system clock source, directly or through the + * PLL). + */ +#if !defined(HSE_VALUE) +#define HSE_VALUE 16000000UL /*!< Value of the External oscillator in Hz */ +#endif /* HSE_VALUE */ + +#if !defined(HSE_STARTUP_TIMEOUT) +#define HSE_STARTUP_TIMEOUT 100UL /*!< Time out for HSE start up, in ms */ +#endif /* HSE_STARTUP_TIMEOUT */ + +/** + * @brief Internal Multiple Speed oscillator (MSI) default value. + * This value is the default MSI range value after Reset. + */ +#if !defined(MSI_VALUE) +#define MSI_VALUE 4000000UL /*!< Value of the Internal oscillator in Hz*/ +#endif /* MSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI) value. + * This value is used by the RCC HAL module to compute the system + * frequency (when HSI is used as system clock source, directly or through the + * PLL). + */ +#if !defined(HSI_VALUE) +#define HSI_VALUE 16000000UL /*!< Value of the Internal oscillator in Hz*/ +#endif /* HSI_VALUE */ + +/** + * @brief Internal High Speed oscillator (HSI48) value for USB FS, SDMMC and + * RNG. This internal oscillator is mainly dedicated to provide a high precision + * clock to the USB peripheral by means of a special Clock Recovery System (CRS) + * circuitry. When the CRS is not used, the HSI48 RC oscillator runs on it + * default frequency which is subject to manufacturing process variations. + */ +#if !defined(HSI48_VALUE) +#define HSI48_VALUE \ + 48000000UL /*!< Value of the Internal High Speed oscillator for USB \ + FS/SDMMC/RNG in Hz. The real value my vary depending on \ + manufacturing process variations.*/ +#endif /* HSI48_VALUE */ + +/** + * @brief Internal Low Speed oscillator (LSI) value. + */ +#if !defined(LSI_VALUE) +#define LSI_VALUE 32000UL /*!< LSI Typical Value in Hz*/ +#endif /* LSI_VALUE */ /*!< Value of the Internal Low Speed oscillator in Hz \ + The real value may vary depending on the \ + variations in voltage and temperature.*/ +/** + * @brief External Low Speed oscillator (LSE) value. + * This value is used by the UART, RTC HAL module to compute the system + * frequency + */ +#if !defined(LSE_VALUE) +#define LSE_VALUE \ + 32768UL /*!< Value of the External Low Speed oscillator in Hz */ +#endif /* LSE_VALUE */ + +#if !defined(LSE_STARTUP_TIMEOUT) +#define LSE_STARTUP_TIMEOUT 5000UL /*!< Time out for LSE start up, in ms */ +#endif /* LSE_STARTUP_TIMEOUT */ + +/** + * @brief External clock source for SAI1 peripheral + * This value is used by the RCC HAL module to compute the SAI1 & SAI2 + * clock source frequency. + */ +#if !defined(EXTERNAL_SAI1_CLOCK_VALUE) +#define EXTERNAL_SAI1_CLOCK_VALUE \ + 48000UL /*!< Value of the SAI1 External clock source in Hz*/ +#endif /* EXTERNAL_SAI1_CLOCK_VALUE */ + +/* Tip: To avoid modifying this file each time you need to use different HSE, + === you can define the HSE value in your toolchain compiler preprocessor. */ + +/* ########################### System Configuration ######################### */ +/** + * @brief This is the HAL system configuration section + */ + +#define VDD_VALUE 3300UL /*!< Value of VDD in mv */ +#define TICK_INT_PRIORITY \ + (15UL) /*!< tick interrupt priority (lowest by default) */ +#define USE_RTOS 0U +#define PREFETCH_ENABLE 1U /*!< Enable prefetch */ + +/* ########################## Assert Selection ############################## */ +/** + * @brief Uncomment the line below to expanse the "assert_param" macro in the + * HAL drivers code + */ + +/* #define USE_FULL_ASSERT 1U */ + +/* ################## Register callback feature configuration ############### */ +/** + * @brief Set below the peripheral configuration to "1U" to add the support + * of HAL callback registration/unregistration feature for the HAL + * driver(s). This allows user application to provide specific callback + * functions thanks to HAL_PPP_RegisterCallback() rather than overwriting + * the default weak callback functions (see each stm32u5xx_hal_ppp.h file + * for possible callback identifiers defined in HAL_PPP_CallbackIDTypeDef + * for each PPP peripheral). + */ +#define USE_HAL_ADC_REGISTER_CALLBACKS \ + 0U /* ADC register callback disabled */ +#define USE_HAL_COMP_REGISTER_CALLBACKS \ + 0U /* COMP register callback disabled */ +#define USE_HAL_CORDIC_REGISTER_CALLBACKS \ + 0U /* CORDIC register callback disabled */ +#define USE_HAL_CRYP_REGISTER_CALLBACKS \ + 0U /* CRYP register callback disabled */ +#define USE_HAL_DAC_REGISTER_CALLBACKS \ + 0U /* DAC register callback disabled */ +#define USE_HAL_DCMI_REGISTER_CALLBACKS \ + 0U /* DCMI register callback disabled */ +#define USE_HAL_DMA2D_REGISTER_CALLBACKS \ + 0U /* DMA2D register callback disabled */ +#define USE_HAL_DSI_REGISTER_CALLBACKS \ + 0U /* DSI register callback disabled */ +#define USE_HAL_ETH_REGISTER_CALLBACKS \ + 0U /* ETH register callback disabled */ +#define USE_HAL_FDCAN_REGISTER_CALLBACKS \ + 0U /* FDCAN register callback disabled */ +#define USE_HAL_FMAC_REGISTER_CALLBACKS \ + 0U /* FMAC register callback disabled */ +#define USE_HAL_HASH_REGISTER_CALLBACKS \ + 0U /* HASH register callback disabled */ +#define USE_HAL_HCD_REGISTER_CALLBACKS \ + 0U /* HCD register callback disabled */ +#define USE_HAL_GFXMMU_REGISTER_CALLBACKS \ + 0U /* GFXMMU register callback disabled */ +#define USE_HAL_GPU2D_REGISTER_CALLBACKS \ + 0U /* GPU2D register callback disabled */ +#define USE_HAL_I2C_REGISTER_CALLBACKS \ + 0U /* I2C register callback disabled */ +#define USE_HAL_IWDG_REGISTER_CALLBACKS \ + 0U /* IWDG register callback disabled */ +#define USE_HAL_IRDA_REGISTER_CALLBACKS \ + 0U /* IRDA register callback disabled */ +#define USE_HAL_LPTIM_REGISTER_CALLBACKS \ + 0U /* LPTIM register callback disabled */ +#define USE_HAL_LTDC_REGISTER_CALLBACKS \ + 0U /* LTDC register callback disabled */ +#define USE_HAL_MDF_REGISTER_CALLBACKS \ + 0U /* MDF register callback disabled */ +#define USE_HAL_MMC_REGISTER_CALLBACKS \ + 0U /* MMC register callback disabled */ +#define USE_HAL_NAND_REGISTER_CALLBACKS \ + 0U /* NAND register callback disabled */ +#define USE_HAL_NOR_REGISTER_CALLBACKS \ + 0U /* NOR register callback disabled */ +#define USE_HAL_OPAMP_REGISTER_CALLBACKS \ + 0U /* MDIO register callback disabled */ +#define USE_HAL_OTFDEC_REGISTER_CALLBACKS \ + 0U /* OTFDEC register callback disabled */ +#define USE_HAL_PCD_REGISTER_CALLBACKS \ + 0U /* PCD register callback disabled */ +#define USE_HAL_PKA_REGISTER_CALLBACKS \ + 0U /* PKA register callback disabled */ +#define USE_HAL_RAMCFG_REGISTER_CALLBACKS \ + 0U /* RAMCFG register callback disabled */ +#define USE_HAL_RNG_REGISTER_CALLBACKS \ + 0U /* RNG register callback disabled */ +#define USE_HAL_RTC_REGISTER_CALLBACKS \ + 0U /* RTC register callback disabled */ +#define USE_HAL_SAI_REGISTER_CALLBACKS \ + 0U /* SAI register callback disabled */ +#define USE_HAL_SD_REGISTER_CALLBACKS \ + 0U /* SD register callback disabled */ +#define USE_HAL_SDRAM_REGISTER_CALLBACKS \ + 0U /* SDRAM register callback disabled */ +#define USE_HAL_SMARTCARD_REGISTER_CALLBACKS \ + 0U /* SMARTCARD register callback disabled */ +#define USE_HAL_SMBUS_REGISTER_CALLBACKS \ + 0U /* SMBUS register callback disabled */ +#define USE_HAL_SPI_REGISTER_CALLBACKS \ + 0U /* SPI register callback disabled */ +#define USE_HAL_SRAM_REGISTER_CALLBACKS \ + 0U /* SRAM register callback disabled */ +#define USE_HAL_TIM_REGISTER_CALLBACKS \ + 0U /* TIM register callback disabled */ +#define USE_HAL_TSC_REGISTER_CALLBACKS \ + 0U /* TSC register callback disabled */ +#define USE_HAL_UART_REGISTER_CALLBACKS \ + 0U /* UART register callback disabled */ +#define USE_HAL_USART_REGISTER_CALLBACKS \ + 0U /* USART register callback disabled */ +#define USE_HAL_WWDG_REGISTER_CALLBACKS \ + 0U /* WWDG register callback disabled */ +#define USE_HAL_OSPI_REGISTER_CALLBACKS \ + 0U /* OSPI register callback disabled */ +/* ################## SPI peripheral configuration ########################## */ + +/* CRC FEATURE: Use to activate CRC feature inside HAL SPI Driver + * Activated: CRC code is present inside driver + * Deactivated: CRC code cleaned from driver + */ +#define USE_SPI_CRC 0U + +/* ################## SDMMC peripheral configuration ######################### + */ + +#define USE_SD_TRANSCEIVER 0U /*!< use uSD Transceiver */ + +/* Includes ------------------------------------------------------------------*/ +/** + * @brief Include module's header file + */ + +#ifdef HAL_RCC_MODULE_ENABLED +#include "stm32u5xx_hal_rcc.h" +#endif /* HAL_RCC_MODULE_ENABLED */ + +#ifdef HAL_GPIO_MODULE_ENABLED +#include "stm32u5xx_hal_gpio.h" +#endif /* HAL_GPIO_MODULE_ENABLED */ + +#ifdef HAL_ICACHE_MODULE_ENABLED +#include "stm32u5xx_hal_icache.h" +#endif /* HAL_ICACHE_MODULE_ENABLED */ + +#ifdef HAL_DCACHE_MODULE_ENABLED +#include "stm32u5xx_hal_dcache.h" +#endif /* HAL_DCACHE_MODULE_ENABLED */ + +#ifdef HAL_GTZC_MODULE_ENABLED +#include "stm32u5xx_hal_gtzc.h" +#endif /* HAL_GTZC_MODULE_ENABLED */ + +#ifdef HAL_DMA_MODULE_ENABLED +#include "stm32u5xx_hal_dma.h" +#endif /* HAL_DMA_MODULE_ENABLED */ + +#ifdef HAL_DMA2D_MODULE_ENABLED +#include "stm32u5xx_hal_dma2d.h" +#endif /* HAL_DMA2D_MODULE_ENABLED */ + +#ifdef HAL_DSI_MODULE_ENABLED +#include "stm32u5xx_hal_dsi.h" +#endif /* HAL_DSI_MODULE_ENABLED */ + +#ifdef HAL_CORTEX_MODULE_ENABLED +#include "stm32u5xx_hal_cortex.h" +#endif /* HAL_CORTEX_MODULE_ENABLED */ + +#ifdef HAL_PKA_MODULE_ENABLED +#include "stm32u5xx_hal_pka.h" +#endif /* HAL_PKA_MODULE_ENABLED */ + +#ifdef HAL_ADC_MODULE_ENABLED +#include "stm32u5xx_hal_adc.h" +#endif /* HAL_ADC_MODULE_ENABLED */ + +#ifdef HAL_COMP_MODULE_ENABLED +#include "stm32u5xx_hal_comp.h" +#endif /* HAL_COMP_MODULE_ENABLED */ + +#ifdef HAL_CRC_MODULE_ENABLED +#include "stm32u5xx_hal_crc.h" +#endif /* HAL_CRC_MODULE_ENABLED */ + +#ifdef HAL_CRYP_MODULE_ENABLED +#include "stm32u5xx_hal_cryp.h" +#endif /* HAL_CRYP_MODULE_ENABLED */ + +#ifdef HAL_DAC_MODULE_ENABLED +#include "stm32u5xx_hal_dac.h" +#endif /* HAL_DAC_MODULE_ENABLED */ + +#ifdef HAL_FLASH_MODULE_ENABLED +#include "stm32u5xx_hal_flash.h" +#endif /* HAL_FLASH_MODULE_ENABLED */ + +#ifdef HAL_HASH_MODULE_ENABLED +#include "stm32u5xx_hal_hash.h" +#endif /* HAL_HASH_MODULE_ENABLED */ + +#ifdef HAL_SRAM_MODULE_ENABLED +#include "stm32u5xx_hal_sram.h" +#endif /* HAL_SRAM_MODULE_ENABLED */ + +#ifdef HAL_MMC_MODULE_ENABLED +#include "stm32u5xx_hal_mmc.h" +#endif /* HAL_MMC_MODULE_ENABLED */ + +#ifdef HAL_NOR_MODULE_ENABLED +#include "stm32u5xx_hal_nor.h" +#endif /* HAL_NOR_MODULE_ENABLED */ + +#ifdef HAL_NAND_MODULE_ENABLED +#include "stm32u5xx_hal_nand.h" +#endif /* HAL_NAND_MODULE_ENABLED */ + +#ifdef HAL_I2C_MODULE_ENABLED +#include "stm32u5xx_hal_i2c.h" +#endif /* HAL_I2C_MODULE_ENABLED */ + +#ifdef HAL_IWDG_MODULE_ENABLED +#include "stm32u5xx_hal_iwdg.h" +#endif /* HAL_IWDG_MODULE_ENABLED */ + +#ifdef HAL_LPTIM_MODULE_ENABLED +#include "stm32u5xx_hal_lptim.h" +#endif /* HAL_LPTIM_MODULE_ENABLED */ + +#ifdef HAL_LTDC_MODULE_ENABLED +#include "stm32u5xx_hal_ltdc.h" +#endif /* HAL_LTDC_MODULE_ENABLED */ + +#ifdef HAL_OPAMP_MODULE_ENABLED +#include "stm32u5xx_hal_opamp.h" +#endif /* HAL_OPAMP_MODULE_ENABLED */ + +#ifdef HAL_PWR_MODULE_ENABLED +#include "stm32u5xx_hal_pwr.h" +#endif /* HAL_PWR_MODULE_ENABLED */ + +#ifdef HAL_OSPI_MODULE_ENABLED +#include "stm32u5xx_hal_ospi.h" +#endif /* HAL_OSPI_MODULE_ENABLED */ + +#ifdef HAL_RNG_MODULE_ENABLED +#include "stm32u5xx_hal_rng.h" +#endif /* HAL_RNG_MODULE_ENABLED */ + +#ifdef HAL_RTC_MODULE_ENABLED +#include "stm32u5xx_hal_rtc.h" +#endif /* HAL_RTC_MODULE_ENABLED */ + +#ifdef HAL_SAI_MODULE_ENABLED +#include "stm32u5xx_hal_sai.h" +#endif /* HAL_SAI_MODULE_ENABLED */ + +#ifdef HAL_SD_MODULE_ENABLED +#include "stm32u5xx_hal_sd.h" +#endif /* HAL_SD_MODULE_ENABLED */ + +#ifdef HAL_SMBUS_MODULE_ENABLED +#include "stm32u5xx_hal_smbus.h" +#endif /* HAL_SMBUS_MODULE_ENABLED */ + +#ifdef HAL_SPI_MODULE_ENABLED +#include "stm32u5xx_hal_spi.h" +#endif /* HAL_SPI_MODULE_ENABLED */ + +#ifdef HAL_TIM_MODULE_ENABLED +#include "stm32u5xx_hal_tim.h" +#endif /* HAL_TIM_MODULE_ENABLED */ + +#ifdef HAL_TSC_MODULE_ENABLED +#include "stm32u5xx_hal_tsc.h" +#endif /* HAL_TSC_MODULE_ENABLED */ + +#ifdef HAL_UART_MODULE_ENABLED +#include "stm32u5xx_hal_uart.h" +#endif /* HAL_UART_MODULE_ENABLED */ + +#ifdef HAL_USART_MODULE_ENABLED +#include "stm32u5xx_hal_usart.h" +#endif /* HAL_USART_MODULE_ENABLED */ + +#ifdef HAL_IRDA_MODULE_ENABLED +#include "stm32u5xx_hal_irda.h" +#endif /* HAL_IRDA_MODULE_ENABLED */ + +#ifdef HAL_SMARTCARD_MODULE_ENABLED +#include "stm32u5xx_hal_smartcard.h" +#endif /* HAL_SMARTCARD_MODULE_ENABLED */ + +#ifdef HAL_WWDG_MODULE_ENABLED +#include "stm32u5xx_hal_wwdg.h" +#endif /* HAL_WWDG_MODULE_ENABLED */ + +#ifdef HAL_PCD_MODULE_ENABLED +#include "stm32u5xx_hal_pcd.h" +#endif /* HAL_PCD_MODULE_ENABLED */ + +#ifdef HAL_HCD_MODULE_ENABLED +#include "stm32u5xx_hal_hcd.h" +#endif /* HAL_HCD_MODULE_ENABLED */ + +#ifdef HAL_CORDIC_MODULE_ENABLED +#include "stm32u5xx_hal_cordic.h" +#endif /* HAL_CORDIC_MODULE_ENABLED */ + +#ifdef HAL_DCMI_MODULE_ENABLED +#include "stm32u5xx_hal_dcmi.h" +#endif /* HAL_DCMI_MODULE_ENABLED */ + +#ifdef HAL_EXTI_MODULE_ENABLED +#include "stm32u5xx_hal_exti.h" +#endif /* HAL_EXTI_MODULE_ENABLED */ + +#ifdef HAL_FDCAN_MODULE_ENABLED +#include "stm32u5xx_hal_fdcan.h" +#endif /* HAL_FDCAN_MODULE_ENABLED */ + +#ifdef HAL_FMAC_MODULE_ENABLED +#include "stm32u5xx_hal_fmac.h" +#endif /* HAL_FMAC_MODULE_ENABLED */ + +#ifdef HAL_GFXMMU_MODULE_ENABLED +#include "stm32u5xx_hal_gfxmmu.h" +#endif /* HAL_GFXMMU_MODULE_ENABLED */ + +#ifdef HAL_GPU2D_MODULE_ENABLED +#include "stm32u5xx_hal_gpu2d.h" +#endif /* HAL_GPU2D_MODULE_ENABLED */ + +#ifdef HAL_OTFDEC_MODULE_ENABLED +#include "stm32u5xx_hal_otfdec.h" +#endif /* HAL_OTFDEC_MODULE_ENABLED */ + +#ifdef HAL_PSSI_MODULE_ENABLED +#include "stm32u5xx_hal_pssi.h" +#endif /* HAL_PSSI_MODULE_ENABLED */ + +#ifdef HAL_RAMCFG_MODULE_ENABLED +#include "stm32u5xx_hal_ramcfg.h" +#endif /* HAL_RAMCFG_MODULE_ENABLED */ + +#ifdef HAL_MDF_MODULE_ENABLED +#include "stm32u5xx_hal_mdf.h" +#endif /* HAL_MDF_MODULE_ENABLED */ + +#ifdef HAL_XSPI_MODULE_ENABLED +#include "stm32u5xx_hal_xspi.h" +#endif /* HAL_XSPI_MODULE_ENABLED */ + +/* Exported macro ------------------------------------------------------------*/ +#ifdef USE_FULL_ASSERT +/** + * @brief The assert_param macro is used for function's parameters check. + * @param expr: If expr is false, it calls assert_failed function + * which reports the name of the source file and the source + * line number of the call that failed. + * If expr is true, it returns no value. + * @retval None + */ +#define assert_param(expr) \ + ((expr) ? (void)0U : assert_failed((uint8_t *)__FILE__, __LINE__)) +/* Exported functions ------------------------------------------------------- */ +void assert_failed(uint8_t *file, uint32_t line); +#else +#define assert_param(expr) ((void)0U) +#endif /* USE_FULL_ASSERT */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32U5xx_HAL_CONF_H */ diff --git a/core/embed/trezorhal/stm32u5/stm32u5xx_hal_sd.c b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_sd.c new file mode 100644 index 00000000000..b6f64f26c8a --- /dev/null +++ b/core/embed/trezorhal/stm32u5/stm32u5xx_hal_sd.c @@ -0,0 +1,4083 @@ +// clang-format off +/** + ****************************************************************************** + * @file stm32u5xx_hal_sd.c + * @author MCD Application Team + * @brief SD card HAL module driver. + * This file provides firmware functions to manage the following + * functionalities of the Secure Digital (SD) peripheral: + * + Initialization and de-initialization functions + * + IO operation functions + * + Peripheral Control functions + * + Peripheral State functions + * + ****************************************************************************** + * @attention + * + * Copyright (c) 2021 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + @verbatim + ============================================================================== + ##### How to use this driver ##### + ============================================================================== + [..] + This driver implements a high level communication layer for read and write from/to + this memory. The needed STM32 hardware resources (SDMMC and GPIO) are performed by + the user in HAL_SD_MspInit() function (MSP layer). + Basically, the MSP layer configuration should be the same as we provide in the + examples. + You can easily tailor this configuration according to hardware resources. + + [..] + This driver is a generic layered driver for SDMMC memories which uses the HAL + SDMMC driver functions to interface with SD and uSD cards devices. + It is used as follows: + + (#)Initialize the SDMMC low level resources by implementing the HAL_SD_MspInit() API: + (##) Enable the SDMMC interface clock using __HAL_RCC_SDMMC_CLK_ENABLE(); + (##) SDMMC pins configuration for SD card + (+++) Enable the clock for the SDMMC GPIOs using the functions __HAL_RCC_GPIOx_CLK_ENABLE(); + (+++) Configure these SDMMC pins as alternate function pull-up using HAL_GPIO_Init() + and according to your pin assignment; + (##) NVIC configuration if you need to use interrupt process (HAL_SD_ReadBlocks_IT() + and HAL_SD_WriteBlocks_IT() APIs). + (+++) Configure the SDMMC interrupt priorities using function HAL_NVIC_SetPriority(); + (+++) Enable the NVIC SDMMC IRQs using function HAL_NVIC_EnableIRQ() + (+++) SDMMC interrupts are managed using the macros __HAL_SD_ENABLE_IT() + and __HAL_SD_DISABLE_IT() inside the communication process. + (+++) SDMMC interrupts pending bits are managed using the macros __HAL_SD_GET_IT() + and __HAL_SD_CLEAR_IT() + (##) No general propose DMA Configuration is needed, an Internal DMA for SDMMC Peripheral are used. + + (#) At this stage, you can perform SD read/write/erase operations after SD card initialization + + + *** SD Card Initialization and configuration *** + ================================================ + [..] + To initialize the SD Card, use the HAL_SD_Init() function. It Initializes + SDMMC Peripheral(STM32 side) and the SD Card, and put it into StandBy State (Ready for data transfer). + This function provide the following operations: + + (#) Apply the SD Card initialization process at 400KHz and check the SD Card + type (Standard Capacity or High Capacity). You can change or adapt this + frequency by adjusting the "ClockDiv" field. + The SD Card frequency (SDMMC_CK) is computed as follows: + + SDMMC_CK = SDMMCCLK / (2 * ClockDiv) + + In initialization mode and according to the SD Card standard, + make sure that the SDMMC_CK frequency doesn't exceed 400KHz. + + This phase of initialization is done through SDMMC_Init() and + SDMMC_PowerState_ON() SDMMC low level APIs. + + (#) Initialize the SD card. The API used is HAL_SD_InitCard(). + This phase allows the card initialization and identification + and check the SD Card type (Standard Capacity or High Capacity) + The initialization flow is compatible with SD standard. + + This API (HAL_SD_InitCard()) could be used also to reinitialize the card in case + of plug-off plug-in. + + (#) Configure the SD Card Data transfer frequency. You can change or adapt this + frequency by adjusting the "ClockDiv" field. + In transfer mode and according to the SD Card standard, make sure that the + SDMMC_CK frequency doesn't exceed 25MHz and 100MHz in High-speed mode switch. + + (#) Select the corresponding SD Card according to the address read with the step 2. + + (#) Configure the SD Card in wide bus mode: 4-bits data. + + *** SD Card Read operation *** + ============================== + [..] + (+) You can read from SD card in polling mode by using function HAL_SD_ReadBlocks(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to ensure that the transfer is done correctly. The check is done + through HAL_SD_GetCardState() function for SD card state. + + (+) You can read from SD card in DMA mode by using function HAL_SD_ReadBlocks_DMA(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to ensure that the transfer is done correctly. The check is done + through HAL_SD_GetCardState() function for SD card state. + You could also check the DMA transfer process through the SD Rx interrupt event. + + (+) You can read from SD card in Interrupt mode by using function HAL_SD_ReadBlocks_IT(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to ensure that the transfer is done correctly. The check is done + through HAL_SD_GetCardState() function for SD card state. + You could also check the IT transfer process through the SD Rx interrupt event. + + *** SD Card Write operation *** + =============================== + [..] + (+) You can write to SD card in polling mode by using function HAL_SD_WriteBlocks(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to ensure that the transfer is done correctly. The check is done + through HAL_SD_GetCardState() function for SD card state. + + (+) You can write to SD card in DMA mode by using function HAL_SD_WriteBlocks_DMA(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to ensure that the transfer is done correctly. The check is done + through HAL_SD_GetCardState() function for SD card state. + You could also check the DMA transfer process through the SD Tx interrupt event. + + (+) You can write to SD card in Interrupt mode by using function HAL_SD_WriteBlocks_IT(). + This function support only 512-bytes block length (the block size should be + chosen as 512 bytes). + You can choose either one block read operation or multiple block read operation + by adjusting the "NumberOfBlocks" parameter. + After this, you have to ensure that the transfer is done correctly. The check is done + through HAL_SD_GetCardState() function for SD card state. + You could also check the IT transfer process through the SD Tx interrupt event. + + *** SD card status *** + ====================== + [..] + (+) The SD Status contains status bits that are related to the SD Memory + Card proprietary features. To get SD card status use the HAL_SD_GetCardStatus(). + + *** SD card information *** + =========================== + [..] + (+) To get SD card information, you can use the function HAL_SD_GetCardInfo(). + It returns useful information about the SD card such as block size, card type, + block number ... + + *** SD card CSD register *** + ============================ + (+) The HAL_SD_GetCardCSD() API allows to get the parameters of the CSD register. + Some of the CSD parameters are useful for card initialization and identification. + + *** SD card CID register *** + ============================ + (+) The HAL_SD_GetCardCID() API allows to get the parameters of the CID register. + Some of the CSD parameters are useful for card initialization and identification. + + *** SD HAL driver macros list *** + ================================== + [..] + Below the list of most used macros in SD HAL driver. + + (+) __HAL_SD_ENABLE_IT: Enable the SD device interrupt + (+) __HAL_SD_DISABLE_IT: Disable the SD device interrupt + (+) __HAL_SD_GET_FLAG:Check whether the specified SD flag is set or not + (+) __HAL_SD_CLEAR_FLAG: Clear the SD's pending flags + + (@) You can refer to the SD HAL driver header file for more useful macros + + *** Callback registration *** + ============================================= + [..] + The compilation define USE_HAL_SD_REGISTER_CALLBACKS when set to 1 + allows the user to configure dynamically the driver callbacks. + + Use Functions HAL_SD_RegisterCallback() to register a user callback, + it allows to register following callbacks: + (+) TxCpltCallback : callback when a transmission transfer is completed. + (+) RxCpltCallback : callback when a reception transfer is completed. + (+) ErrorCallback : callback when error occurs. + (+) AbortCpltCallback : callback when abort is completed. + (+) Read_DMADblBuf0CpltCallback : callback when the DMA reception of first buffer is completed. + (+) Read_DMADblBuf1CpltCallback : callback when the DMA reception of second buffer is completed. + (+) Write_DMADblBuf0CpltCallback : callback when the DMA transmission of first buffer is completed. + (+) Write_DMADblBuf1CpltCallback : callback when the DMA transmission of second buffer is completed. + (+) MspInitCallback : SD MspInit. + (+) MspDeInitCallback : SD MspDeInit. + This function takes as parameters the HAL peripheral handle, the Callback ID + and a pointer to the user callback function. + For specific callbacks TransceiverCallback use dedicated register callbacks: + respectively HAL_SD_RegisterTransceiverCallback(). + + Use function HAL_SD_UnRegisterCallback() to reset a callback to the default + weak (overridden) function. It allows to reset following callbacks: + (+) TxCpltCallback : callback when a transmission transfer is completed. + (+) RxCpltCallback : callback when a reception transfer is completed. + (+) ErrorCallback : callback when error occurs. + (+) AbortCpltCallback : callback when abort is completed. + (+) Read_DMALnkLstBufCpltCallback : callback when the DMA reception of linked list node buffer is completed. + (+) Write_DMALnkLstBufCpltCallback : callback when the DMA transmission of linked list node buffer is completed. + (+) MspInitCallback : SD MspInit. + (+) MspDeInitCallback : SD MspDeInit. + This function) takes as parameters the HAL peripheral handle and the Callback ID. + For specific callbacks TransceiverCallback use dedicated unregister callbacks: + respectively HAL_SD_UnRegisterTransceiverCallback(). + + By default, after the HAL_SD_Init and if the state is HAL_SD_STATE_RESET + all callbacks are reset to the corresponding legacy weak (overridden) functions. + Exception done for MspInit and MspDeInit callbacks that are respectively + reset to the legacy weak (overridden) functions in the HAL_SD_Init + and HAL_SD_DeInit only when these callbacks are null (not registered beforehand). + If not, MspInit or MspDeInit are not null, the HAL_SD_Init and HAL_SD_DeInit + keep and use the user MspInit/MspDeInit callbacks (registered beforehand) + + Callbacks can be registered/unregistered in READY state only. + Exception done for MspInit/MspDeInit callbacks that can be registered/unregistered + in READY or RESET state, thus registered (user) MspInit/DeInit callbacks can be used + during the Init/DeInit. + In that case first register the MspInit/MspDeInit user callbacks + using HAL_SD_RegisterCallback before calling HAL_SD_DeInit + or HAL_SD_Init function. + + When The compilation define USE_HAL_SD_REGISTER_CALLBACKS is set to 0 or + not defined, the callback registering feature is not available + and weak (overridden) callbacks are used. + + @endverbatim + ****************************************************************************** + */ + +/* Includes ------------------------------------------------------------------*/ +#include "stm32u5xx_hal.h" + +/** @addtogroup STM32U5xx_HAL_Driver + * @{ + */ + +/** @addtogroup SD + * @{ + */ + +#if defined (SDMMC1) || defined (SDMMC2) +#ifdef HAL_SD_MODULE_ENABLED + +/* Private typedef -----------------------------------------------------------*/ +/* Private define ------------------------------------------------------------*/ +/** @addtogroup SD_Private_Defines + * @{ + */ +/* Frequencies used in the driver for clock divider calculation */ +#define SD_INIT_FREQ 400000U /* Initialization phase : 400 kHz max */ +#define SD_NORMAL_SPEED_FREQ 25000000U /* Normal speed phase : 25 MHz max */ +#define SD_HIGH_SPEED_FREQ 50000000U /* High speed phase : 50 MHz max */ +/* Private macro -------------------------------------------------------------*/ +#if defined (DLYB_SDMMC1) && defined (DLYB_SDMMC2) +#define SD_GET_DLYB_INSTANCE(SDMMC_INSTANCE) (((SDMMC_INSTANCE) == SDMMC1)? \ + DLYB_SDMMC1 : DLYB_SDMMC2 ) +#elif defined (DLYB_SDMMC1) +#define SD_GET_DLYB_INSTANCE(SDMMC_INSTANCE) ( DLYB_SDMMC1 ) +#endif /* (DLYB_SDMMC1) && defined (DLYB_SDMMC2) */ + +/** + * @} + */ + +/* Private variables ---------------------------------------------------------*/ +/* Private function prototypes -----------------------------------------------*/ +/* Private functions ---------------------------------------------------------*/ +/** @defgroup SD_Private_Functions SD Private Functions + * @{ + */ +static uint32_t SD_InitCard(SD_HandleTypeDef *hsd); +static uint32_t SD_PowerON(SD_HandleTypeDef *hsd); +static uint32_t SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus); +static uint32_t SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus); +static uint32_t SD_WideBus_Enable(SD_HandleTypeDef *hsd); +static uint32_t SD_WideBus_Disable(SD_HandleTypeDef *hsd); +static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR); +static void SD_PowerOFF(SD_HandleTypeDef *hsd); +static void SD_Write_IT(SD_HandleTypeDef *hsd); +static void SD_Read_IT(SD_HandleTypeDef *hsd); +static uint32_t SD_SwitchSpeed(SD_HandleTypeDef *hsd, uint32_t SwitchSpeedMode); +#if (USE_SD_TRANSCEIVER != 0U) +static uint32_t SD_UltraHighSpeed(SD_HandleTypeDef *hsd, uint32_t UltraHighSpeedMode); +static uint32_t SD_DDR_Mode(SD_HandleTypeDef *hsd); +#endif /* USE_SD_TRANSCEIVER */ +/** + * @} + */ + +/* Exported functions --------------------------------------------------------*/ +/** @addtogroup SD_Exported_Functions + * @{ + */ + +/** @addtogroup SD_Exported_Functions_Group1 + * @brief Initialization and de-initialization functions + * +@verbatim + ============================================================================== + ##### Initialization and de-initialization functions ##### + ============================================================================== + [..] + This section provides functions allowing to initialize/de-initialize the SD + card device to be ready for use. + +@endverbatim + * @{ + */ + +/** + * @brief Initializes the SD according to the specified parameters in the + SD_HandleTypeDef and create the associated handle. + * @param hsd: Pointer to the SD handle + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_Init(SD_HandleTypeDef *hsd) +{ + HAL_SD_CardStatusTypeDef CardStatus; + uint32_t speedgrade; + uint32_t unitsize; + uint32_t tickstart; + + /* Check the SD handle allocation */ + if (hsd == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance)); + assert_param(IS_SDMMC_CLOCK_EDGE(hsd->Init.ClockEdge)); + assert_param(IS_SDMMC_CLOCK_POWER_SAVE(hsd->Init.ClockPowerSave)); + assert_param(IS_SDMMC_BUS_WIDE(hsd->Init.BusWide)); + assert_param(IS_SDMMC_HARDWARE_FLOW_CONTROL(hsd->Init.HardwareFlowControl)); + assert_param(IS_SDMMC_CLKDIV(hsd->Init.ClockDiv)); + + if (hsd->State == HAL_SD_STATE_RESET) + { + /* Allocate lock resource and initialize it */ + hsd->Lock = HAL_UNLOCKED; + +#if (USE_SD_TRANSCEIVER != 0U) + /* Force SDMMC_TRANSCEIVER_PRESENT for Legacy usage */ + if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_UNKNOWN) + { + hsd->Init.TranceiverPresent = SDMMC_TRANSCEIVER_PRESENT; + } +#endif /*USE_SD_TRANSCEIVER */ +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + /* Reset Callback pointers in HAL_SD_STATE_RESET only */ + hsd->TxCpltCallback = HAL_SD_TxCpltCallback; + hsd->RxCpltCallback = HAL_SD_RxCpltCallback; + hsd->ErrorCallback = HAL_SD_ErrorCallback; + hsd->AbortCpltCallback = HAL_SD_AbortCallback; + hsd->Read_DMALnkLstBufCpltCallback = HAL_SDEx_Read_DMALnkLstBufCpltCallback; + hsd->Write_DMALnkLstBufCpltCallback = HAL_SDEx_Write_DMALnkLstBufCpltCallback; +#if (USE_SD_TRANSCEIVER != 0U) + if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT) + { + hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback; + } +#endif /* USE_SD_TRANSCEIVER */ + + if (hsd->MspInitCallback == NULL) + { + hsd->MspInitCallback = HAL_SD_MspInit; + } + + /* Init the low level hardware */ + hsd->MspInitCallback(hsd); +#else + /* Init the low level hardware : GPIO, CLOCK, CORTEX...etc */ + HAL_SD_MspInit(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + + hsd->State = HAL_SD_STATE_PROGRAMMING; + + /* Initialize the Card parameters */ + if (HAL_SD_InitCard(hsd) != HAL_OK) + { + return HAL_ERROR; + } + + if (HAL_SD_GetCardStatus(hsd, &CardStatus) != HAL_OK) + { + return HAL_ERROR; + } + /* Get Initial Card Speed from Card Status*/ + speedgrade = CardStatus.UhsSpeedGrade; + unitsize = CardStatus.UhsAllocationUnitSize; + if ((hsd->SdCard.CardType == CARD_SDHC_SDXC) && ((speedgrade != 0U) || (unitsize != 0U))) + { + hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED; + } + else + { + if (hsd->SdCard.CardType == CARD_SDHC_SDXC) + { + hsd->SdCard.CardSpeed = CARD_HIGH_SPEED; + } + else + { + hsd->SdCard.CardSpeed = CARD_NORMAL_SPEED; + } + + } + /* Configure the bus wide */ + if (HAL_SD_ConfigWideBusOperation(hsd, hsd->Init.BusWide) != HAL_OK) + { + return HAL_ERROR; + } + + /* Verify that SD card is ready to use after Initialization */ + tickstart = HAL_GetTick(); + while ((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER)) + { + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_TIMEOUT; + } + } + + /* Initialize the error code */ + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + /* Initialize the SD operation */ + hsd->Context = SD_CONTEXT_NONE; + + /* Initialize the SD state */ + hsd->State = HAL_SD_STATE_READY; + + return HAL_OK; +} + +/** + * @brief Initializes the SD Card. + * @param hsd: Pointer to SD handle + * @note This function initializes the SD card. It could be used when a card + re-initialization is needed. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_InitCard(SD_HandleTypeDef *hsd) +{ + uint32_t errorstate; + SD_InitTypeDef Init; + uint32_t sdmmc_clk; + + /* Default SDMMC peripheral configuration for SD card initialization */ + Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; + Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; + Init.BusWide = SDMMC_BUS_WIDE_1B; + Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; + + /* Init Clock should be less or equal to 400Khz*/ + sdmmc_clk = HSI48_VALUE; + if (sdmmc_clk == 0U) + { + hsd->State = HAL_SD_STATE_READY; + hsd->ErrorCode = SDMMC_ERROR_INVALID_PARAMETER; + return HAL_ERROR; + } + Init.ClockDiv = sdmmc_clk / (2U * SD_INIT_FREQ); + +#if (USE_SD_TRANSCEIVER != 0U) + Init.TranceiverPresent = hsd->Init.TranceiverPresent; + + if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT) + { + /* Set Transceiver polarity */ + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; + } +#elif defined (USE_SD_DIRPOL) + /* Set Transceiver polarity */ + hsd->Instance->POWER |= SDMMC_POWER_DIRPOL; +#endif /* USE_SD_TRANSCEIVER */ + + /* Initialize SDMMC peripheral interface with default configuration */ + (void)SDMMC_Init(hsd->Instance, Init); + + /* Set Power State to ON */ + (void)SDMMC_PowerState_ON(hsd->Instance); + + /* wait 74 Cycles: required power up waiting time before starting + the SD initialization sequence */ + if (Init.ClockDiv != 0U) + { + sdmmc_clk = sdmmc_clk / (2U * Init.ClockDiv); + } + + if (sdmmc_clk != 0U) + { + HAL_Delay(1U + (74U * 1000U / (sdmmc_clk))); + } + + /* Identify card operating voltage */ + errorstate = SD_PowerON(hsd); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->State = HAL_SD_STATE_READY; + hsd->ErrorCode |= errorstate; + return HAL_ERROR; + } + + /* Card initialization */ + errorstate = SD_InitCard(hsd); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->State = HAL_SD_STATE_READY; + hsd->ErrorCode |= errorstate; + return HAL_ERROR; + } + + /* Set Block Size for Card */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + + return HAL_OK; +} + +/** + * @brief De-Initializes the SD card. + * @param hsd: Pointer to SD handle + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_DeInit(SD_HandleTypeDef *hsd) +{ + /* Check the SD handle allocation */ + if (hsd == NULL) + { + return HAL_ERROR; + } + + /* Check the parameters */ + assert_param(IS_SDMMC_ALL_INSTANCE(hsd->Instance)); + + hsd->State = HAL_SD_STATE_BUSY; + +#if (USE_SD_TRANSCEIVER != 0U) + /* Deactivate the 1.8V Mode */ + if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT) + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + if (hsd->DriveTransceiver_1_8V_Callback == NULL) + { + hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback; + } + hsd->DriveTransceiver_1_8V_Callback(RESET); +#else + HAL_SD_DriveTransceiver_1_8V_Callback(RESET); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } +#endif /* USE_SD_TRANSCEIVER */ + + /* Set SD power state to off */ + SD_PowerOFF(hsd); + +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + if (hsd->MspDeInitCallback == NULL) + { + hsd->MspDeInitCallback = HAL_SD_MspDeInit; + } + + /* DeInit the low level hardware */ + hsd->MspDeInitCallback(hsd); +#else + /* De-Initialize the MSP layer */ + HAL_SD_MspDeInit(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + + hsd->ErrorCode = HAL_SD_ERROR_NONE; + hsd->State = HAL_SD_STATE_RESET; + + return HAL_OK; +} + + +/** + * @brief Initializes the SD MSP. + * @param hsd: Pointer to SD handle + * @retval None + */ +__weak void HAL_SD_MspInit(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SD_MspInit could be implemented in the user file + */ +} + +/** + * @brief De-Initialize SD MSP. + * @param hsd: Pointer to SD handle + * @retval None + */ +__weak void HAL_SD_MspDeInit(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SD_MspDeInit could be implemented in the user file + */ +} + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group2 + * @brief Data transfer functions + * +@verbatim + ============================================================================== + ##### IO operation functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to manage the data + transfer from/to SD card. + +@endverbatim + * @{ + */ + +/** + * @brief Reads block(s) from a specified address in a card. The Data transfer + * is managed by polling mode. + * @note This API should be followed by a check on the card state through + * HAL_SD_GetCardState(). + * @param hsd: Pointer to SD handle + * @param pData: pointer to the buffer that will contain the received data + * @param BlockAdd: Block Address from where data is to be read + * @param NumberOfBlocks: Number of SD blocks to read + * @param Timeout: Specify timeout value + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, + uint32_t Timeout) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t tickstart = HAL_GetTick(); + uint32_t count; + uint32_t data; + uint32_t dataremaining; + uint32_t add = BlockAdd; + uint8_t *tempbuff = pData; + + if (NULL == pData) + { + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + return HAL_ERROR; + } + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_BUSY; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0U; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= BLOCKSIZE; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = NumberOfBlocks * BLOCKSIZE; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + + /* Read block(s) in polling mode */ + if (NumberOfBlocks > 1U) + { + hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK; + + /* Read Multi Block command */ + errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add); + } + else + { + hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK; + + /* Read Single Block command */ + errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add); + } + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + + /* Poll on SDMMC flags */ + dataremaining = config.DataLength; + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + { + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) && (dataremaining >= SDMMC_FIFO_SIZE)) + { + /* Read data from SDMMC Rx FIFO */ + for (count = 0U; count < (SDMMC_FIFO_SIZE / 4U); count++) + { + data = SDMMC_ReadFIFO(hsd->Instance); + *tempbuff = (uint8_t)(data & 0xFFU); + tempbuff++; + *tempbuff = (uint8_t)((data >> 8U) & 0xFFU); + tempbuff++; + *tempbuff = (uint8_t)((data >> 16U) & 0xFFU); + tempbuff++; + *tempbuff = (uint8_t)((data >> 24U) & 0xFFU); + tempbuff++; + } + dataremaining -= SDMMC_FIFO_SIZE; + } + + if (((HAL_GetTick() - tickstart) >= Timeout) || (Timeout == 0U)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_TIMEOUT; + } + } + __SDMMC_CMDTRANS_DISABLE(hsd->Instance); + + /* Send stop transmission command in case of multiblock read */ + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U)) + { + if (hsd->SdCard.CardType != CARD_SECURED) + { + /* Send stop transmission command */ + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + } + } + + /* Get error state */ + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + else + { + /* Nothing to do */ + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + hsd->State = HAL_SD_STATE_READY; + + return HAL_OK; + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + return HAL_ERROR; + } +} + +/** + * @brief Allows to write block(s) to a specified address in a card. The Data + * transfer is managed by polling mode. + * @note This API should be followed by a check on the card state through + * HAL_SD_GetCardState(). + * @param hsd: Pointer to SD handle + * @param pData: pointer to the buffer that will contain the data to transmit + * @param BlockAdd: Block Address where data will be written + * @param NumberOfBlocks: Number of SD blocks to write + * @param Timeout: Specify timeout value + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_WriteBlocks(SD_HandleTypeDef *hsd, const uint8_t *pData, uint32_t BlockAdd, + uint32_t NumberOfBlocks, uint32_t Timeout) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t tickstart = HAL_GetTick(); + uint32_t count; + uint32_t data; + uint32_t dataremaining; + uint32_t add = BlockAdd; + const uint8_t *tempbuff = pData; + + if (NULL == pData) + { + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + return HAL_ERROR; + } + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_BUSY; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0U; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= BLOCKSIZE; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = NumberOfBlocks * BLOCKSIZE; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + + /* Write Blocks in Polling mode */ + if (NumberOfBlocks > 1U) + { + hsd->Context = SD_CONTEXT_WRITE_MULTIPLE_BLOCK; + + /* Write Multi Block command */ + errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); + } + else + { + hsd->Context = SD_CONTEXT_WRITE_SINGLE_BLOCK; + + /* Write Single Block command */ + errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add); + } + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + + /* Write block(s) in polling mode */ + dataremaining = config.DataLength; + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | + SDMMC_FLAG_DATAEND)) + { + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) && (dataremaining >= SDMMC_FIFO_SIZE)) + { + /* Write data to SDMMC Tx FIFO */ + for (count = 0U; count < (SDMMC_FIFO_SIZE / 4U); count++) + { + data = (uint32_t)(*tempbuff); + tempbuff++; + data |= ((uint32_t)(*tempbuff) << 8U); + tempbuff++; + data |= ((uint32_t)(*tempbuff) << 16U); + tempbuff++; + data |= ((uint32_t)(*tempbuff) << 24U); + tempbuff++; + (void)SDMMC_WriteFIFO(hsd->Instance, &data); + } + dataremaining -= SDMMC_FIFO_SIZE; + } + + if (((HAL_GetTick() - tickstart) >= Timeout) || (Timeout == 0U)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_TIMEOUT; + } + } + __SDMMC_CMDTRANS_DISABLE(hsd->Instance); + + /* Send stop transmission command in case of multiblock write */ + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) && (NumberOfBlocks > 1U)) + { + if (hsd->SdCard.CardType != CARD_SECURED) + { + /* Send stop transmission command */ + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + } + } + + /* Get error state */ + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXUNDERR)) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + else + { + /* Nothing to do */ + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + hsd->State = HAL_SD_STATE_READY; + + return HAL_OK; + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_BUSY; + return HAL_ERROR; + } +} + +/** + * @brief Reads block(s) from a specified address in a card. The Data transfer + * is managed in interrupt mode. + * @note This API should be followed by a check on the card state through + * HAL_SD_GetCardState(). + * @note You could also check the IT transfer process through the SD Rx + * interrupt event. + * @param hsd: Pointer to SD handle + * @param pData: Pointer to the buffer that will contain the received data + * @param BlockAdd: Block Address from where data is to be read + * @param NumberOfBlocks: Number of blocks to read. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_ReadBlocks_IT(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, + uint32_t NumberOfBlocks) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t add = BlockAdd; + + if (NULL == pData) + { + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + return HAL_ERROR; + } + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_BUSY; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0U; + + hsd->pRxBuffPtr = pData; + hsd->RxXferSize = BLOCKSIZE * NumberOfBlocks; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= BLOCKSIZE; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + + /* Read Blocks in IT mode */ + if (NumberOfBlocks > 1U) + { + hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_IT); + + /* Read Multi Block command */ + errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add); + } + else + { + hsd->Context = (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_IT); + + /* Read Single Block command */ + errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add); + } + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + + __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND | + SDMMC_FLAG_RXFIFOHF)); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Writes block(s) to a specified address in a card. The Data transfer + * is managed in interrupt mode. + * @note This API should be followed by a check on the card state through + * HAL_SD_GetCardState(). + * @note You could also check the IT transfer process through the SD Tx + * interrupt event. + * @param hsd: Pointer to SD handle + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param BlockAdd: Block Address where data will be written + * @param NumberOfBlocks: Number of blocks to write + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_WriteBlocks_IT(SD_HandleTypeDef *hsd, const uint8_t *pData, uint32_t BlockAdd, + uint32_t NumberOfBlocks) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t add = BlockAdd; + + if (NULL == pData) + { + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + return HAL_ERROR; + } + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_BUSY; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0U; + + hsd->pTxBuffPtr = pData; + hsd->TxXferSize = BLOCKSIZE * NumberOfBlocks; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= BLOCKSIZE; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + + /* Write Blocks in Polling mode */ + if (NumberOfBlocks > 1U) + { + hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_IT); + + /* Write Multi Block command */ + errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); + } + else + { + hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_IT); + + /* Write Single Block command */ + errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add); + } + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + + /* Enable transfer interrupts */ + __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND | + SDMMC_FLAG_TXFIFOHE)); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Reads block(s) from a specified address in a card. The Data transfer + * is managed by DMA mode. + * @note This API should be followed by a check on the card state through + * HAL_SD_GetCardState(). + * @note You could also check the DMA transfer process through the SD Rx + * interrupt event. + * @param hsd: Pointer SD handle + * @param pData: Pointer to the buffer that will contain the received data + * @param BlockAdd: Block Address from where data is to be read + * @param NumberOfBlocks: Number of blocks to read. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_ReadBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, + uint32_t NumberOfBlocks) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t add = BlockAdd; + + if (NULL == pData) + { + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + return HAL_ERROR; + } + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_BUSY; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0U; + + hsd->pRxBuffPtr = pData; + hsd->RxXferSize = BLOCKSIZE * NumberOfBlocks; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= BLOCKSIZE; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + hsd->Instance->IDMABASER = (uint32_t) pData ; + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_SINGLE_BUFF; + + /* Read Blocks in DMA mode */ + if (NumberOfBlocks > 1U) + { + hsd->Context = (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA); + + /* Read Multi Block command */ + errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, add); + } + else + { + hsd->Context = (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_DMA); + + /* Read Single Block command */ + errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, add); + } + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + + /* Enable transfer interrupts */ + __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND)); + + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Writes block(s) to a specified address in a card. The Data transfer + * is managed by DMA mode. + * @note This API should be followed by a check on the card state through + * HAL_SD_GetCardState(). + * @note You could also check the DMA transfer process through the SD Tx + * interrupt event. + * @param hsd: Pointer to SD handle + * @param pData: Pointer to the buffer that will contain the data to transmit + * @param BlockAdd: Block Address where data will be written + * @param NumberOfBlocks: Number of blocks to write + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, const uint8_t *pData, uint32_t BlockAdd, + uint32_t NumberOfBlocks) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t add = BlockAdd; + + if (NULL == pData) + { + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + return HAL_ERROR; + } + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + if ((add + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_BUSY; + + /* Initialize data control register */ + hsd->Instance->DCTRL = 0U; + + hsd->pTxBuffPtr = pData; + hsd->TxXferSize = BLOCKSIZE * NumberOfBlocks; + + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + add *= BLOCKSIZE; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = BLOCKSIZE * NumberOfBlocks; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_CARD; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_DISABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + + + __SDMMC_CMDTRANS_ENABLE(hsd->Instance); + + hsd->Instance->IDMABASER = (uint32_t) pData ; + hsd->Instance->IDMACTRL = SDMMC_ENABLE_IDMA_SINGLE_BUFF; + + /* Write Blocks in Polling mode */ + if (NumberOfBlocks > 1U) + { + hsd->Context = (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA); + + /* Write Multi Block command */ + errorstate = SDMMC_CmdWriteMultiBlock(hsd->Instance, add); + } + else + { + hsd->Context = (SD_CONTEXT_WRITE_SINGLE_BLOCK | SD_CONTEXT_DMA); + + /* Write Single Block command */ + errorstate = SDMMC_CmdWriteSingleBlock(hsd->Instance, add); + } + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + return HAL_ERROR; + } + + /* Enable transfer interrupts */ + __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND)); + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief Erases the specified memory area of the given SD card. + * @note This API should be followed by a check on the card state through + * HAL_SD_GetCardState(). + * @param hsd: Pointer to SD handle + * @param BlockStartAdd: Start Block address + * @param BlockEndAdd: End Block address + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_Erase(SD_HandleTypeDef *hsd, uint32_t BlockStartAdd, uint32_t BlockEndAdd) +{ + uint32_t errorstate; + uint32_t start_add = BlockStartAdd; + uint32_t end_add = BlockEndAdd; + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->ErrorCode = HAL_SD_ERROR_NONE; + + if (end_add < start_add) + { + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + return HAL_ERROR; + } + + if (end_add > (hsd->SdCard.LogBlockNbr)) + { + hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_BUSY; + + /* Check if the card command class supports erase command */ + if (((hsd->SdCard.Class) & SDMMC_CCCC_ERASE) == 0U) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + + if ((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + + /* Get start and end block for high capacity cards */ + if (hsd->SdCard.CardType != CARD_SDHC_SDXC) + { + start_add *= BLOCKSIZE; + end_add *= BLOCKSIZE; + } + + /* According to sd-card spec 1.0 ERASE_GROUP_START (CMD32) and erase_group_end(CMD33) */ + if (hsd->SdCard.CardType != CARD_SECURED) + { + /* Send CMD32 SD_ERASE_GRP_START with argument as addr */ + errorstate = SDMMC_CmdSDEraseStartAdd(hsd->Instance, start_add); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + + /* Send CMD33 SD_ERASE_GRP_END with argument as addr */ + errorstate = SDMMC_CmdSDEraseEndAdd(hsd->Instance, end_add); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + } + + /* Send CMD38 ERASE */ + errorstate = SDMMC_CmdErase(hsd->Instance, 0UL); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + + hsd->State = HAL_SD_STATE_READY; + + return HAL_OK; + } + else + { + return HAL_BUSY; + } +} + +/** + * @brief This function handles SD card interrupt request. + * @param hsd: Pointer to SD handle + * @retval None + */ +void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd) +{ + uint32_t errorstate; + uint32_t context = hsd->Context; + + /* Check for SDMMC interrupt flags */ + if ((__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) != RESET) && ((context & SD_CONTEXT_IT) != 0U)) + { + SD_Read_IT(hsd); + } + + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND) != RESET) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DATAEND); + + __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_DATAEND | SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | \ + SDMMC_IT_TXUNDERR | SDMMC_IT_RXOVERR | SDMMC_IT_TXFIFOHE | \ + SDMMC_IT_RXFIFOHF); + + __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_IDMABTC); + __SDMMC_CMDTRANS_DISABLE(hsd->Instance); + + if ((context & SD_CONTEXT_IT) != 0U) + { + if (((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)) + { + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= errorstate; +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->ErrorCallback(hsd); +#else + HAL_SD_ErrorCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + if (((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U)) + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->RxCpltCallback(hsd); +#else + HAL_SD_RxCpltCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + else + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->TxCpltCallback(hsd); +#else + HAL_SD_TxCpltCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + } + else if ((context & SD_CONTEXT_DMA) != 0U) + { + hsd->Instance->DLEN = 0; + hsd->Instance->DCTRL = 0; + hsd->Instance->IDMACTRL = SDMMC_DISABLE_IDMA; + + /* Stop Transfer for Write Multi blocks or Read Multi blocks */ + if (((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)) + { + errorstate = SDMMC_CmdStopTransfer(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= errorstate; +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->ErrorCallback(hsd); +#else + HAL_SD_ErrorCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + } + + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; + if (((context & SD_CONTEXT_WRITE_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)) + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->TxCpltCallback(hsd); +#else + HAL_SD_TxCpltCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + if (((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U)) + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->RxCpltCallback(hsd); +#else + HAL_SD_RxCpltCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + } + else + { + /* Nothing to do */ + } + } + + else if ((__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_TXFIFOHE) != RESET) && ((context & SD_CONTEXT_IT) != 0U)) + { + SD_Write_IT(hsd); + } + + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_RXOVERR | + SDMMC_FLAG_TXUNDERR) != RESET) + { + /* Set Error code */ + if (__HAL_SD_GET_FLAG(hsd, SDMMC_IT_DCRCFAIL) != RESET) + { + hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL; + } + if (__HAL_SD_GET_FLAG(hsd, SDMMC_IT_DTIMEOUT) != RESET) + { + hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT; + } + if (__HAL_SD_GET_FLAG(hsd, SDMMC_IT_RXOVERR) != RESET) + { + hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN; + } + if (__HAL_SD_GET_FLAG(hsd, SDMMC_IT_TXUNDERR) != RESET) + { + hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN; + } + + /* Clear All flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + /* Disable all interrupts */ + __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_DATAEND | SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | \ + SDMMC_IT_TXUNDERR | SDMMC_IT_RXOVERR); + + __SDMMC_CMDTRANS_DISABLE(hsd->Instance); + hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST; + hsd->Instance->CMD |= SDMMC_CMD_CMDSTOP; + hsd->ErrorCode |= SDMMC_CmdStopTransfer(hsd->Instance); + hsd->Instance->CMD &= ~(SDMMC_CMD_CMDSTOP); + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DABORT); + + if ((context & SD_CONTEXT_IT) != 0U) + { + /* Set the SD state to ready to be able to start again the process */ + hsd->State = HAL_SD_STATE_READY; + hsd->Context = SD_CONTEXT_NONE; +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->ErrorCallback(hsd); +#else + HAL_SD_ErrorCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + else if ((context & SD_CONTEXT_DMA) != 0U) + { + if (hsd->ErrorCode != HAL_SD_ERROR_NONE) + { + /* Disable Internal DMA */ + __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_IDMABTC); + hsd->Instance->IDMACTRL = SDMMC_DISABLE_IDMA; + + /* Set the SD state to ready to be able to start again the process */ + hsd->State = HAL_SD_STATE_READY; +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->ErrorCallback(hsd); +#else + HAL_SD_ErrorCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + } + else + { + /* Nothing to do */ + } + } + + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_IDMABTC) != RESET) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_IDMABTC); + + if ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U) + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->Write_DMALnkLstBufCpltCallback(hsd); +#else + HAL_SDEx_Write_DMALnkLstBufCpltCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + else /* SD_CONTEXT_READ_MULTIPLE_BLOCK */ + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->Read_DMALnkLstBufCpltCallback(hsd); +#else + HAL_SDEx_Read_DMALnkLstBufCpltCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + } + else + { + /* Nothing to do */ + } +} + +/** + * @brief return the SD state + * @param hsd: Pointer to sd handle + * @retval HAL state + */ +HAL_SD_StateTypeDef HAL_SD_GetState(const SD_HandleTypeDef *hsd) +{ + return hsd->State; +} + +/** + * @brief Return the SD error code + * @param hsd : Pointer to a SD_HandleTypeDef structure that contains + * the configuration information. + * @retval SD Error Code + */ +uint32_t HAL_SD_GetError(const SD_HandleTypeDef *hsd) +{ + return hsd->ErrorCode; +} + +/** + * @brief Tx Transfer completed callbacks + * @param hsd: Pointer to SD handle + * @retval None + */ +__weak void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SD_TxCpltCallback can be implemented in the user file + */ +} + +/** + * @brief Rx Transfer completed callbacks + * @param hsd: Pointer SD handle + * @retval None + */ +__weak void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SD_RxCpltCallback can be implemented in the user file + */ +} + +/** + * @brief SD error callbacks + * @param hsd: Pointer SD handle + * @retval None + */ +__weak void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SD_ErrorCallback can be implemented in the user file + */ +} + +/** + * @brief SD Abort callbacks + * @param hsd: Pointer SD handle + * @retval None + */ +__weak void HAL_SD_AbortCallback(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SD_AbortCallback can be implemented in the user file + */ +} + +#if (USE_SD_TRANSCEIVER != 0U) +/** + * @brief Enable/Disable the SD Transceiver 1.8V Mode Callback. + * @param status: Voltage Switch State + * @retval None + */ +__weak void HAL_SD_DriveTransceiver_1_8V_Callback(FlagStatus status) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(status); + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SD_EnableTransceiver could be implemented in the user file + */ +} +#endif /* USE_SD_TRANSCEIVER */ + +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) +/** + * @brief Register a User SD Callback + * To be used instead of the weak (overridden) predefined callback + * @note The HAL_SD_RegisterCallback() may be called before HAL_SD_Init() in + * HAL_SD_STATE_RESET to register callbacks for HAL_SD_MSP_INIT_CB_ID + * and HAL_SD_MSP_DEINIT_CB_ID. + * @param hsd : SD handle + * @param CallbackID : ID of the callback to be registered + * This parameter can be one of the following values: + * @arg @ref HAL_SD_TX_CPLT_CB_ID SD Tx Complete Callback ID + * @arg @ref HAL_SD_RX_CPLT_CB_ID SD Rx Complete Callback ID + * @arg @ref HAL_SD_ERROR_CB_ID SD Error Callback ID + * @arg @ref HAL_SD_ABORT_CB_ID SD Abort Callback ID + * @arg @ref HAL_SD_READ_DMA_LNKLST_BUF_CPLT_CB_ID SD DMA Rx Linked List Node buffer Callback ID + * @arg @ref HAL_SD_WRITE_DMA_LNKLST_BUF_CPLT_CB_ID SD DMA Tx Linked List Node buffer Callback ID + * @arg @ref HAL_SD_MSP_INIT_CB_ID SD MspInit Callback ID + * @arg @ref HAL_SD_MSP_DEINIT_CB_ID SD MspDeInit Callback ID + * @param pCallback : pointer to the Callback function + * @retval status + */ +HAL_StatusTypeDef HAL_SD_RegisterCallback(SD_HandleTypeDef *hsd, HAL_SD_CallbackIDTypeDef CallbackID, + pSD_CallbackTypeDef pCallback) +{ + HAL_StatusTypeDef status = HAL_OK; + + if (pCallback == NULL) + { + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + return HAL_ERROR; + } + + if (hsd->State == HAL_SD_STATE_READY) + { + switch (CallbackID) + { + case HAL_SD_TX_CPLT_CB_ID : + hsd->TxCpltCallback = pCallback; + break; + case HAL_SD_RX_CPLT_CB_ID : + hsd->RxCpltCallback = pCallback; + break; + case HAL_SD_ERROR_CB_ID : + hsd->ErrorCallback = pCallback; + break; + case HAL_SD_ABORT_CB_ID : + hsd->AbortCpltCallback = pCallback; + break; + case HAL_SD_READ_DMA_LNKLST_BUF_CPLT_CB_ID : + hsd->Read_DMALnkLstBufCpltCallback = pCallback; + break; + case HAL_SD_WRITE_DMA_LNKLST_BUF_CPLT_CB_ID : + hsd->Write_DMALnkLstBufCpltCallback = pCallback; + break; + case HAL_SD_MSP_INIT_CB_ID : + hsd->MspInitCallback = pCallback; + break; + case HAL_SD_MSP_DEINIT_CB_ID : + hsd->MspDeInitCallback = pCallback; + break; + default : + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + break; + } + } + else if (hsd->State == HAL_SD_STATE_RESET) + { + switch (CallbackID) + { + case HAL_SD_MSP_INIT_CB_ID : + hsd->MspInitCallback = pCallback; + break; + case HAL_SD_MSP_DEINIT_CB_ID : + hsd->MspDeInitCallback = pCallback; + break; + default : + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + break; + } + } + else + { + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + } + + return status; +} + +/** + * @brief Unregister a User SD Callback + * SD Callback is redirected to the weak (overridden) predefined callback + * @note The HAL_SD_UnRegisterCallback() may be called before HAL_SD_Init() in + * HAL_SD_STATE_RESET to register callbacks for HAL_SD_MSP_INIT_CB_ID + * and HAL_SD_MSP_DEINIT_CB_ID. + * @param hsd : SD handle + * @param CallbackID : ID of the callback to be unregistered + * This parameter can be one of the following values: + * @arg @ref HAL_SD_TX_CPLT_CB_ID SD Tx Complete Callback ID + * @arg @ref HAL_SD_RX_CPLT_CB_ID SD Rx Complete Callback ID + * @arg @ref HAL_SD_ERROR_CB_ID SD Error Callback ID + * @arg @ref HAL_SD_ABORT_CB_ID SD Abort Callback ID + * @arg @ref HAL_SD_READ_DMA_LNKLST_BUF_CPLT_CB_ID SD DMA Rx Linked List Node buffer Callback ID + * @arg @ref HAL_SD_WRITE_DMA_LNKLST_BUF_CPLT_CB_ID SD DMA Tx Linked List Node buffer Callback ID + * @arg @ref HAL_SD_MSP_INIT_CB_ID SD MspInit Callback ID + * @arg @ref HAL_SD_MSP_DEINIT_CB_ID SD MspDeInit Callback ID + * @retval status + */ +HAL_StatusTypeDef HAL_SD_UnRegisterCallback(SD_HandleTypeDef *hsd, HAL_SD_CallbackIDTypeDef CallbackID) +{ + HAL_StatusTypeDef status = HAL_OK; + + if (hsd->State == HAL_SD_STATE_READY) + { + switch (CallbackID) + { + case HAL_SD_TX_CPLT_CB_ID : + hsd->TxCpltCallback = HAL_SD_TxCpltCallback; + break; + case HAL_SD_RX_CPLT_CB_ID : + hsd->RxCpltCallback = HAL_SD_RxCpltCallback; + break; + case HAL_SD_ERROR_CB_ID : + hsd->ErrorCallback = HAL_SD_ErrorCallback; + break; + case HAL_SD_ABORT_CB_ID : + hsd->AbortCpltCallback = HAL_SD_AbortCallback; + break; + case HAL_SD_READ_DMA_LNKLST_BUF_CPLT_CB_ID : + hsd->Read_DMALnkLstBufCpltCallback = HAL_SDEx_Read_DMALnkLstBufCpltCallback; + break; + case HAL_SD_WRITE_DMA_LNKLST_BUF_CPLT_CB_ID : + hsd->Write_DMALnkLstBufCpltCallback = HAL_SDEx_Write_DMALnkLstBufCpltCallback; + break; + case HAL_SD_MSP_INIT_CB_ID : + hsd->MspInitCallback = HAL_SD_MspInit; + break; + case HAL_SD_MSP_DEINIT_CB_ID : + hsd->MspDeInitCallback = HAL_SD_MspDeInit; + break; + default : + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + break; + } + } + else if (hsd->State == HAL_SD_STATE_RESET) + { + switch (CallbackID) + { + case HAL_SD_MSP_INIT_CB_ID : + hsd->MspInitCallback = HAL_SD_MspInit; + break; + case HAL_SD_MSP_DEINIT_CB_ID : + hsd->MspDeInitCallback = HAL_SD_MspDeInit; + break; + default : + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + break; + } + } + else + { + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + } + + return status; +} + +#if (USE_SD_TRANSCEIVER != 0U) +/** + * @brief Register a User SD Transceiver Callback + * To be used instead of the weak (overridden) predefined callback + * @param hsd : SD handle + * @param pCallback : pointer to the Callback function + * @retval status + */ +HAL_StatusTypeDef HAL_SD_RegisterTransceiverCallback(SD_HandleTypeDef *hsd, pSD_TransceiverCallbackTypeDef pCallback) +{ + HAL_StatusTypeDef status = HAL_OK; + + if (pCallback == NULL) + { + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + return HAL_ERROR; + } + + /* Process locked */ + __HAL_LOCK(hsd); + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->DriveTransceiver_1_8V_Callback = pCallback; + } + else + { + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hsd); + return status; +} + +/** + * @brief Unregister a User SD Transceiver Callback + * SD Callback is redirected to the weak (overridden) predefined callback + * @param hsd : SD handle + * @retval status + */ +HAL_StatusTypeDef HAL_SD_UnRegisterTransceiverCallback(SD_HandleTypeDef *hsd) +{ + HAL_StatusTypeDef status = HAL_OK; + + /* Process locked */ + __HAL_LOCK(hsd); + + if (hsd->State == HAL_SD_STATE_READY) + { + hsd->DriveTransceiver_1_8V_Callback = HAL_SD_DriveTransceiver_1_8V_Callback; + } + else + { + /* Update the error code */ + hsd->ErrorCode |= HAL_SD_ERROR_INVALID_CALLBACK; + /* update return status */ + status = HAL_ERROR; + } + + /* Release Lock */ + __HAL_UNLOCK(hsd); + return status; +} +#endif /* USE_SD_TRANSCEIVER */ +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + +/** + * @} + */ + +/** @addtogroup SD_Exported_Functions_Group3 + * @brief management functions + * +@verbatim + ============================================================================== + ##### Peripheral Control functions ##### + ============================================================================== + [..] + This subsection provides a set of functions allowing to control the SD card + operations and get the related information + +@endverbatim + * @{ + */ + +/** + * @brief Returns information the information of the card which are stored on + * the CID register. + * @param hsd: Pointer to SD handle + * @param pCID: Pointer to a HAL_SD_CardCIDTypeDef structure that + * contains all CID register parameters + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_GetCardCID(SD_HandleTypeDef *hsd, HAL_SD_CardCIDTypeDef *pCID) +{ + pCID->ManufacturerID = (uint8_t)((hsd->CID[0] & 0xFF000000U) >> 24U); + + pCID->OEM_AppliID = (uint16_t)((hsd->CID[0] & 0x00FFFF00U) >> 8U); + + pCID->ProdName1 = (((hsd->CID[0] & 0x000000FFU) << 24U) | ((hsd->CID[1] & 0xFFFFFF00U) >> 8U)); + + pCID->ProdName2 = (uint8_t)(hsd->CID[1] & 0x000000FFU); + + pCID->ProdRev = (uint8_t)((hsd->CID[2] & 0xFF000000U) >> 24U); + + pCID->ProdSN = (((hsd->CID[2] & 0x00FFFFFFU) << 8U) | ((hsd->CID[3] & 0xFF000000U) >> 24U)); + + pCID->Reserved1 = (uint8_t)((hsd->CID[3] & 0x00F00000U) >> 20U); + + pCID->ManufactDate = (uint16_t)((hsd->CID[3] & 0x000FFF00U) >> 8U); + + pCID->CID_CRC = (uint8_t)((hsd->CID[3] & 0x000000FEU) >> 1U); + + pCID->Reserved2 = 1U; + + return HAL_OK; +} + +/** + * @brief Returns information the information of the card which are stored on + * the CSD register. + * @param hsd: Pointer to SD handle + * @param pCSD: Pointer to a HAL_SD_CardCSDTypeDef structure that + * contains all CSD register parameters + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_GetCardCSD(SD_HandleTypeDef *hsd, HAL_SD_CardCSDTypeDef *pCSD) +{ + pCSD->CSDStruct = (uint8_t)((hsd->CSD[0] & 0xC0000000U) >> 30U); + + pCSD->SysSpecVersion = (uint8_t)((hsd->CSD[0] & 0x3C000000U) >> 26U); + + pCSD->Reserved1 = (uint8_t)((hsd->CSD[0] & 0x03000000U) >> 24U); + + pCSD->TAAC = (uint8_t)((hsd->CSD[0] & 0x00FF0000U) >> 16U); + + pCSD->NSAC = (uint8_t)((hsd->CSD[0] & 0x0000FF00U) >> 8U); + + pCSD->MaxBusClkFrec = (uint8_t)(hsd->CSD[0] & 0x000000FFU); + + pCSD->CardComdClasses = (uint16_t)((hsd->CSD[1] & 0xFFF00000U) >> 20U); + + pCSD->RdBlockLen = (uint8_t)((hsd->CSD[1] & 0x000F0000U) >> 16U); + + pCSD->PartBlockRead = (uint8_t)((hsd->CSD[1] & 0x00008000U) >> 15U); + + pCSD->WrBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00004000U) >> 14U); + + pCSD->RdBlockMisalign = (uint8_t)((hsd->CSD[1] & 0x00002000U) >> 13U); + + pCSD->DSRImpl = (uint8_t)((hsd->CSD[1] & 0x00001000U) >> 12U); + + pCSD->Reserved2 = 0U; /*!< Reserved */ + + if (hsd->SdCard.CardType == CARD_SDSC) + { + pCSD->DeviceSize = (((hsd->CSD[1] & 0x000003FFU) << 2U) | ((hsd->CSD[2] & 0xC0000000U) >> 30U)); + + pCSD->MaxRdCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x38000000U) >> 27U); + + pCSD->MaxRdCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x07000000U) >> 24U); + + pCSD->MaxWrCurrentVDDMin = (uint8_t)((hsd->CSD[2] & 0x00E00000U) >> 21U); + + pCSD->MaxWrCurrentVDDMax = (uint8_t)((hsd->CSD[2] & 0x001C0000U) >> 18U); + + pCSD->DeviceSizeMul = (uint8_t)((hsd->CSD[2] & 0x00038000U) >> 15U); + + hsd->SdCard.BlockNbr = (pCSD->DeviceSize + 1U) ; + hsd->SdCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U)); + hsd->SdCard.BlockSize = (1UL << (pCSD->RdBlockLen & 0x0FU)); + + hsd->SdCard.LogBlockNbr = (hsd->SdCard.BlockNbr) * ((hsd->SdCard.BlockSize) / BLOCKSIZE); + hsd->SdCard.LogBlockSize = BLOCKSIZE; + } + else if (hsd->SdCard.CardType == CARD_SDHC_SDXC) + { + /* Byte 7 */ + pCSD->DeviceSize = (((hsd->CSD[1] & 0x0000003FU) << 16U) | ((hsd->CSD[2] & 0xFFFF0000U) >> 16U)); + + hsd->SdCard.BlockNbr = ((pCSD->DeviceSize + 1U) * 1024U); + hsd->SdCard.LogBlockNbr = hsd->SdCard.BlockNbr; + hsd->SdCard.BlockSize = BLOCKSIZE; + hsd->SdCard.LogBlockSize = hsd->SdCard.BlockSize; + } + else + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + hsd->State = HAL_SD_STATE_READY; + return HAL_ERROR; + } + + pCSD->EraseGrSize = (uint8_t)((hsd->CSD[2] & 0x00004000U) >> 14U); + + pCSD->EraseGrMul = (uint8_t)((hsd->CSD[2] & 0x00003F80U) >> 7U); + + pCSD->WrProtectGrSize = (uint8_t)(hsd->CSD[2] & 0x0000007FU); + + pCSD->WrProtectGrEnable = (uint8_t)((hsd->CSD[3] & 0x80000000U) >> 31U); + + pCSD->ManDeflECC = (uint8_t)((hsd->CSD[3] & 0x60000000U) >> 29U); + + pCSD->WrSpeedFact = (uint8_t)((hsd->CSD[3] & 0x1C000000U) >> 26U); + + pCSD->MaxWrBlockLen = (uint8_t)((hsd->CSD[3] & 0x03C00000U) >> 22U); + + pCSD->WriteBlockPaPartial = (uint8_t)((hsd->CSD[3] & 0x00200000U) >> 21U); + + pCSD->Reserved3 = 0; + + pCSD->ContentProtectAppli = (uint8_t)((hsd->CSD[3] & 0x00010000U) >> 16U); + + pCSD->FileFormatGroup = (uint8_t)((hsd->CSD[3] & 0x00008000U) >> 15U); + + pCSD->CopyFlag = (uint8_t)((hsd->CSD[3] & 0x00004000U) >> 14U); + + pCSD->PermWrProtect = (uint8_t)((hsd->CSD[3] & 0x00002000U) >> 13U); + + pCSD->TempWrProtect = (uint8_t)((hsd->CSD[3] & 0x00001000U) >> 12U); + + pCSD->FileFormat = (uint8_t)((hsd->CSD[3] & 0x00000C00U) >> 10U); + + pCSD->ECC = (uint8_t)((hsd->CSD[3] & 0x00000300U) >> 8U); + + pCSD->CSD_CRC = (uint8_t)((hsd->CSD[3] & 0x000000FEU) >> 1U); + + pCSD->Reserved4 = 1; + + return HAL_OK; +} + +/** + * @brief Gets the SD status info.( shall be called if there is no SD transaction ongoing ) + * @param hsd: Pointer to SD handle + * @param pStatus: Pointer to the HAL_SD_CardStatusTypeDef structure that + * will contain the SD card status information + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypeDef *pStatus) +{ + uint32_t sd_status[16]; + uint32_t errorstate; + HAL_StatusTypeDef status = HAL_OK; + + if (hsd->State == HAL_SD_STATE_BUSY) + { + return HAL_ERROR; + } + + errorstate = SD_SendSDStatus(hsd, sd_status); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + hsd->State = HAL_SD_STATE_READY; + status = HAL_ERROR; + } + else + { + pStatus->DataBusWidth = (uint8_t)((sd_status[0] & 0xC0U) >> 6U); + + pStatus->SecuredMode = (uint8_t)((sd_status[0] & 0x20U) >> 5U); + + pStatus->CardType = (uint16_t)(((sd_status[0] & 0x00FF0000U) >> 8U) | ((sd_status[0] & 0xFF000000U) >> 24U)); + + pStatus->ProtectedAreaSize = (((sd_status[1] & 0xFFU) << 24U) | ((sd_status[1] & 0xFF00U) << 8U) | + ((sd_status[1] & 0xFF0000U) >> 8U) | ((sd_status[1] & 0xFF000000U) >> 24U)); + + pStatus->SpeedClass = (uint8_t)(sd_status[2] & 0xFFU); + + pStatus->PerformanceMove = (uint8_t)((sd_status[2] & 0xFF00U) >> 8U); + + pStatus->AllocationUnitSize = (uint8_t)((sd_status[2] & 0xF00000U) >> 20U); + + pStatus->EraseSize = (uint16_t)(((sd_status[2] & 0xFF000000U) >> 16U) | (sd_status[3] & 0xFFU)); + + pStatus->EraseTimeout = (uint8_t)((sd_status[3] & 0xFC00U) >> 10U); + + pStatus->EraseOffset = (uint8_t)((sd_status[3] & 0x0300U) >> 8U); + + pStatus->UhsSpeedGrade = (uint8_t)((sd_status[3] & 0x00F0U) >> 4U); + pStatus->UhsAllocationUnitSize = (uint8_t)(sd_status[3] & 0x000FU) ; + pStatus->VideoSpeedClass = (uint8_t)((sd_status[4] & 0xFF000000U) >> 24U); + } + + /* Set Block Size for Card */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode = errorstate; + hsd->State = HAL_SD_STATE_READY; + status = HAL_ERROR; + } + + + return status; +} + +/** + * @brief Gets the SD card info. + * @param hsd: Pointer to SD handle + * @param pCardInfo: Pointer to the HAL_SD_CardInfoTypeDef structure that + * will contain the SD card status information + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_GetCardInfo(SD_HandleTypeDef *hsd, HAL_SD_CardInfoTypeDef *pCardInfo) +{ + pCardInfo->CardType = (uint32_t)(hsd->SdCard.CardType); + pCardInfo->CardVersion = (uint32_t)(hsd->SdCard.CardVersion); + pCardInfo->Class = (uint32_t)(hsd->SdCard.Class); + pCardInfo->RelCardAdd = (uint32_t)(hsd->SdCard.RelCardAdd); + pCardInfo->BlockNbr = (uint32_t)(hsd->SdCard.BlockNbr); + pCardInfo->BlockSize = (uint32_t)(hsd->SdCard.BlockSize); + pCardInfo->LogBlockNbr = (uint32_t)(hsd->SdCard.LogBlockNbr); + pCardInfo->LogBlockSize = (uint32_t)(hsd->SdCard.LogBlockSize); + + return HAL_OK; +} + +/** + * @brief Enables wide bus operation for the requested card if supported by + * card. + * @param hsd: Pointer to SD handle + * @param WideMode: Specifies the SD card wide bus mode + * This parameter can be one of the following values: + * @arg SDMMC_BUS_WIDE_8B: 8-bit data transfer + * @arg SDMMC_BUS_WIDE_4B: 4-bit data transfer + * @arg SDMMC_BUS_WIDE_1B: 1-bit data transfer + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_ConfigWideBusOperation(SD_HandleTypeDef *hsd, uint32_t WideMode) +{ + SDMMC_InitTypeDef Init; + uint32_t errorstate; + uint32_t sdmmc_clk; + HAL_StatusTypeDef status = HAL_OK; + + /* Check the parameters */ + assert_param(IS_SDMMC_BUS_WIDE(WideMode)); + + /* Change State */ + hsd->State = HAL_SD_STATE_BUSY; + + if (hsd->SdCard.CardType != CARD_SECURED) + { + if (WideMode == SDMMC_BUS_WIDE_8B) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + } + else if (WideMode == SDMMC_BUS_WIDE_4B) + { + errorstate = SD_WideBus_Enable(hsd); + + hsd->ErrorCode |= errorstate; + } + else if (WideMode == SDMMC_BUS_WIDE_1B) + { + errorstate = SD_WideBus_Disable(hsd); + + hsd->ErrorCode |= errorstate; + } + else + { + /* WideMode is not a valid argument*/ + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + } + } + else + { + /* SD Card does not support this feature */ + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + } + + if (hsd->ErrorCode != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + status = HAL_ERROR; + } + else + { + sdmmc_clk = HSI48_VALUE; + if (sdmmc_clk != 0U) + { + /* Configure the SDMMC peripheral */ + Init.ClockEdge = hsd->Init.ClockEdge; + Init.ClockPowerSave = hsd->Init.ClockPowerSave; + Init.BusWide = WideMode; + Init.HardwareFlowControl = hsd->Init.HardwareFlowControl; + + /* Check if user Clock div < Normal speed 25Mhz, no change in Clockdiv */ + if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ))) + { + Init.ClockDiv = hsd->Init.ClockDiv; + } + else if (hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) + { + /* UltraHigh speed SD card,user Clock div */ + Init.ClockDiv = hsd->Init.ClockDiv; + } + else if (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + { + /* High speed SD card, Max Frequency = 50Mhz */ + if (hsd->Init.ClockDiv == 0U) + { + if (sdmmc_clk > SD_HIGH_SPEED_FREQ) + { + Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ); + } + else + { + Init.ClockDiv = hsd->Init.ClockDiv; + } + } + else + { + if ((sdmmc_clk / (2U * hsd->Init.ClockDiv)) > SD_HIGH_SPEED_FREQ) + { + Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ); + } + else + { + Init.ClockDiv = hsd->Init.ClockDiv; + } + } + } + else + { + /* No High speed SD card, Max Frequency = 25Mhz */ + if (hsd->Init.ClockDiv == 0U) + { + if (sdmmc_clk > SD_NORMAL_SPEED_FREQ) + { + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + } + else + { + Init.ClockDiv = hsd->Init.ClockDiv; + } + } + else + { + if ((sdmmc_clk / (2U * hsd->Init.ClockDiv)) > SD_NORMAL_SPEED_FREQ) + { + Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ); + } + else + { + Init.ClockDiv = hsd->Init.ClockDiv; + } + } + } + +#if (USE_SD_TRANSCEIVER != 0U) + Init.TranceiverPresent = hsd->Init.TranceiverPresent; +#endif /* USE_SD_TRANSCEIVER */ + + (void)SDMMC_Init(hsd->Instance, Init); + } + else + { + hsd->ErrorCode |= SDMMC_ERROR_INVALID_PARAMETER; + status = HAL_ERROR; + } + } + + /* Set Block Size for Card */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + status = HAL_ERROR; + } + + /* Change State */ + hsd->State = HAL_SD_STATE_READY; + + return status; +} + +/** + * @brief Configure the speed bus mode + * @param hsd: Pointer to the SD handle + * @param SpeedMode: Specifies the SD card speed bus mode + * This parameter can be one of the following values: + * @arg SDMMC_SPEED_MODE_AUTO: Max speed mode supported by the card + * @arg SDMMC_SPEED_MODE_DEFAULT: Default Speed/SDR12 mode + * @arg SDMMC_SPEED_MODE_HIGH: High Speed/SDR25 mode + * @arg SDMMC_SPEED_MODE_ULTRA: Ultra high speed mode + * @retval HAL status + */ + +HAL_StatusTypeDef HAL_SD_ConfigSpeedBusOperation(SD_HandleTypeDef *hsd, uint32_t SpeedMode) +{ + uint32_t tickstart; + uint32_t errorstate; + HAL_StatusTypeDef status = HAL_OK; + + /* Check the parameters */ + assert_param(IS_SDMMC_SPEED_MODE(SpeedMode)); + /* Change State */ + hsd->State = HAL_SD_STATE_BUSY; + +#if (USE_SD_TRANSCEIVER != 0U) + if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT) + { + switch (SpeedMode) + { + case SDMMC_SPEED_MODE_AUTO: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + hsd->Instance->CLKCR |= SDMMC_CLKCR_BUSSPEED; + /* Enable Ultra High Speed */ + if (SD_UltraHighSpeed(hsd, SDMMC_SDR104_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + if (SD_SwitchSpeed(hsd, SDMMC_SDR25_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + } + } + else if (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) + { + /* Enable High Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR25_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + } + else + { + /*Nothing to do, Use defaultSpeed */ + } + break; + } + case SDMMC_SPEED_MODE_ULTRA_SDR104: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable UltraHigh Speed */ + if (SD_UltraHighSpeed(hsd, SDMMC_SDR104_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + hsd->Instance->CLKCR |= SDMMC_CLKCR_BUSSPEED; + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + break; + } + case SDMMC_SPEED_MODE_ULTRA_SDR50: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable UltraHigh Speed */ + if (SD_UltraHighSpeed(hsd, SDMMC_SDR50_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + hsd->Instance->CLKCR |= SDMMC_CLKCR_BUSSPEED; + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + break; + } + case SDMMC_SPEED_MODE_DDR: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable DDR Mode*/ + if (SD_DDR_Mode(hsd) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + hsd->Instance->CLKCR |= SDMMC_CLKCR_BUSSPEED | SDMMC_CLKCR_DDR; + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + break; + } + case SDMMC_SPEED_MODE_HIGH: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable High Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR25_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + break; + } + case SDMMC_SPEED_MODE_DEFAULT: + { + /* Switch to default Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR12_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + + break; + } + default: + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + status = HAL_ERROR; + break; + } + } + else + { + switch (SpeedMode) + { + case SDMMC_SPEED_MODE_AUTO: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable High Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR25_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + } + else + { + /*Nothing to do, Use defaultSpeed */ + } + break; + } + case SDMMC_SPEED_MODE_HIGH: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable High Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR25_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + break; + } + case SDMMC_SPEED_MODE_DEFAULT: + { + /* Switch to default Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR12_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + + break; + } + case SDMMC_SPEED_MODE_ULTRA: /*not valid without transceiver*/ + default: + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + status = HAL_ERROR; + break; + } + } +#else + switch (SpeedMode) + { + case SDMMC_SPEED_MODE_AUTO: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable High Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR25_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + } + else + { + /*Nothing to do, Use defaultSpeed */ + } + break; + } + case SDMMC_SPEED_MODE_HIGH: + { + if ((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) || + (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) || + (hsd->SdCard.CardType == CARD_SDHC_SDXC)) + { + /* Enable High Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR25_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + } + else + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + break; + } + case SDMMC_SPEED_MODE_DEFAULT: + { + /* Switch to default Speed */ + if (SD_SwitchSpeed(hsd, SDMMC_SDR12_SWITCH_PATTERN) != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_UNSUPPORTED_FEATURE; + status = HAL_ERROR; + } + + break; + } + case SDMMC_SPEED_MODE_ULTRA: /*not valid without transceiver*/ + default: + hsd->ErrorCode |= HAL_SD_ERROR_PARAM; + status = HAL_ERROR; + break; + } +#endif /* USE_SD_TRANSCEIVER */ + + /* Verify that SD card is ready to use after Speed mode switch*/ + tickstart = HAL_GetTick(); + while ((HAL_SD_GetCardState(hsd) != HAL_SD_CARD_TRANSFER)) + { + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_TIMEOUT; + } + } + + /* Set Block Size for Card */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE); + if (errorstate != HAL_SD_ERROR_NONE) + { + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS); + hsd->ErrorCode |= errorstate; + status = HAL_ERROR; + } + + /* Change State */ + hsd->State = HAL_SD_STATE_READY; + return status; +} + +/** + * @brief Gets the current sd card data state. + * @param hsd: pointer to SD handle + * @retval Card state + */ +HAL_SD_CardStateTypeDef HAL_SD_GetCardState(SD_HandleTypeDef *hsd) +{ + uint32_t cardstate; + uint32_t errorstate; + uint32_t resp1 = 0; + + errorstate = SD_SendStatus(hsd, &resp1); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= errorstate; + } + + cardstate = ((resp1 >> 9U) & 0x0FU); + + return (HAL_SD_CardStateTypeDef)cardstate; +} + +/** + * @brief Abort the current transfer and disable the SD. + * @param hsd: pointer to a SD_HandleTypeDef structure that contains + * the configuration information for SD module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_Abort(SD_HandleTypeDef *hsd) +{ + uint32_t error_code; + uint32_t tickstart; + + if (hsd->State == HAL_SD_STATE_BUSY) + { + /* DIsable All interrupts */ + __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_DATAEND | SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | \ + SDMMC_IT_TXUNDERR | SDMMC_IT_RXOVERR); + __SDMMC_CMDTRANS_DISABLE(hsd->Instance); + + /*we will send the CMD12 in all cases in order to stop the data transfers*/ + /*In case the data transfer just finished , the external memory will not respond + and will return HAL_SD_ERROR_CMD_RSP_TIMEOUT*/ + /*In case the data transfer aborted , the external memory will respond and will return HAL_SD_ERROR_NONE*/ + /*Other scenario will return HAL_ERROR*/ + + hsd->ErrorCode = SDMMC_CmdStopTransfer(hsd->Instance); + error_code = hsd->ErrorCode; + if ((error_code != HAL_SD_ERROR_NONE) && (error_code != HAL_SD_ERROR_CMD_RSP_TIMEOUT)) + { + return HAL_ERROR; + } + + tickstart = HAL_GetTick(); + if ((hsd->Instance->DCTRL & SDMMC_DCTRL_DTDIR) == SDMMC_TRANSFER_DIR_TO_CARD) + { + if (hsd->ErrorCode == HAL_SD_ERROR_NONE) + { + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DABORT | SDMMC_FLAG_BUSYD0END)) + { + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_TIMEOUT; + } + } + } + + if (hsd->ErrorCode == HAL_SD_ERROR_CMD_RSP_TIMEOUT) + { + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DATAEND)) + { + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_TIMEOUT; + } + } + } + } + else if ((hsd->Instance->DCTRL & SDMMC_DCTRL_DTDIR) == SDMMC_TRANSFER_DIR_TO_SDMMC) + { + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DABORT | SDMMC_FLAG_DATAEND)) + { + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_TIMEOUT; + } + } + } + else + { + /* Nothing to do*/ + } + + /*The reason of all these while conditions previously is that we need to wait the SDMMC and clear + the appropriate flags that will be set depending of the abort/non abort of the memory */ + /*Not waiting the SDMMC flags will cause the next SDMMC_DISABLE_IDMA to not get cleared + and will result in next SDMMC read/write operation to fail */ + + /*SDMMC ready for clear data flags*/ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_BUSYD0END); + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + /* If IDMA Context, disable Internal DMA */ + hsd->Instance->IDMACTRL = SDMMC_DISABLE_IDMA; + + hsd->State = HAL_SD_STATE_READY; + + /* Initialize the SD operation */ + hsd->Context = SD_CONTEXT_NONE; + } + return HAL_OK; +} + + +/** + * @brief Abort the current transfer and disable the SD (IT mode). + * @param hsd: pointer to a SD_HandleTypeDef structure that contains + * the configuration information for SD module. + * @retval HAL status + */ +HAL_StatusTypeDef HAL_SD_Abort_IT(SD_HandleTypeDef *hsd) +{ + HAL_SD_CardStateTypeDef CardState; + + /* Disable All interrupts */ + __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_DATAEND | SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | \ + SDMMC_IT_TXUNDERR | SDMMC_IT_RXOVERR); + + /* If IDMA Context, disable Internal DMA */ + hsd->Instance->IDMACTRL = SDMMC_DISABLE_IDMA; + + /* Clear All flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + CardState = HAL_SD_GetCardState(hsd); + hsd->State = HAL_SD_STATE_READY; + + if ((CardState == HAL_SD_CARD_RECEIVING) || (CardState == HAL_SD_CARD_SENDING)) + { + hsd->ErrorCode = SDMMC_CmdStopTransfer(hsd->Instance); + } + + if (hsd->ErrorCode != HAL_SD_ERROR_NONE) + { + return HAL_ERROR; + } + else + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->AbortCpltCallback(hsd); +#else + HAL_SD_AbortCallback(hsd); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + } + + return HAL_OK; +} + +/** + * @} + */ + +/** + * @} + */ + +/* Private function ----------------------------------------------------------*/ +/** @addtogroup SD_Private_Functions + * @{ + */ + + +/** + * @brief Initializes the sd card. + * @param hsd: Pointer to SD handle + * @retval SD Card error state + */ +static uint32_t SD_InitCard(SD_HandleTypeDef *hsd) +{ + HAL_SD_CardCSDTypeDef CSD; + uint32_t errorstate; + uint16_t sd_rca = 0U; + uint32_t tickstart = HAL_GetTick(); + + /* Check the power State */ + if (SDMMC_GetPowerState(hsd->Instance) == 0U) + { + /* Power off */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if (hsd->SdCard.CardType != CARD_SECURED) + { + /* Send CMD2 ALL_SEND_CID */ + errorstate = SDMMC_CmdSendCID(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + else + { + /* Get Card identification number data */ + hsd->CID[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + hsd->CID[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + hsd->CID[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + hsd->CID[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + } + } + + if (hsd->SdCard.CardType != CARD_SECURED) + { + /* Send CMD3 SET_REL_ADDR with argument 0 */ + /* SD Card publishes its RCA. */ + while (sd_rca == 0U) + { + errorstate = SDMMC_CmdSetRelAdd(hsd->Instance, &sd_rca); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + if ((HAL_GetTick() - tickstart) >= SDMMC_CMDTIMEOUT) + { + return HAL_SD_ERROR_TIMEOUT; + } + } + } + if (hsd->SdCard.CardType != CARD_SECURED) + { + /* Get the SD card RCA */ + hsd->SdCard.RelCardAdd = sd_rca; + + /* Send CMD9 SEND_CSD with argument as card's RCA */ + errorstate = SDMMC_CmdSendCSD(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + else + { + /* Get Card Specific Data */ + hsd->CSD[0U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + hsd->CSD[1U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2); + hsd->CSD[2U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP3); + hsd->CSD[3U] = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP4); + } + } + + /* Get the Card Class */ + hsd->SdCard.Class = (SDMMC_GetResponse(hsd->Instance, SDMMC_RESP2) >> 20U); + + /* Get CSD parameters */ + if (HAL_SD_GetCardCSD(hsd, &CSD) != HAL_OK) + { + return HAL_SD_ERROR_UNSUPPORTED_FEATURE; + } + + /* Select the Card */ + errorstate = SDMMC_CmdSelDesel(hsd->Instance, (uint32_t)(((uint32_t)hsd->SdCard.RelCardAdd) << 16U)); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* All cards are initialized */ + return HAL_SD_ERROR_NONE; +} + +/** + * @brief Enquires cards about their operating voltage and configures clock + * controls and stores SD information that will be needed in future + * in the SD handle. + * @param hsd: Pointer to SD handle + * @retval error state + */ +static uint32_t SD_PowerON(SD_HandleTypeDef *hsd) +{ + __IO uint32_t count = 0U; + uint32_t response = 0U; + uint32_t validvoltage = 0U; + uint32_t errorstate; +#if (USE_SD_TRANSCEIVER != 0U) + uint32_t tickstart = HAL_GetTick(); +#endif /* USE_SD_TRANSCEIVER */ + + /* CMD0: GO_IDLE_STATE */ + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* CMD8: SEND_IF_COND: Command available only on V2.0 cards */ + errorstate = SDMMC_CmdOperCond(hsd->Instance); + if (errorstate == SDMMC_ERROR_TIMEOUT) /* No response to CMD8 */ + { + hsd->SdCard.CardVersion = CARD_V1_X; + /* CMD0: GO_IDLE_STATE */ + errorstate = SDMMC_CmdGoIdleState(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + } + else + { + hsd->SdCard.CardVersion = CARD_V2_X; + } + + if (hsd->SdCard.CardVersion == CARD_V2_X) + { + /* SEND CMD55 APP_CMD with RCA as 0 */ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + if (errorstate != HAL_SD_ERROR_NONE) + { + return HAL_SD_ERROR_UNSUPPORTED_FEATURE; + } + } + /* SD CARD */ + /* Send ACMD41 SD_APP_OP_COND with Argument 0x80100000 */ + while ((count < SDMMC_MAX_VOLT_TRIAL) && (validvoltage == 0U)) + { + /* SEND CMD55 APP_CMD with RCA as 0 */ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, 0); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Send CMD41 */ + errorstate = SDMMC_CmdAppOperCommand(hsd->Instance, SDMMC_VOLTAGE_WINDOW_SD | SDMMC_HIGH_CAPACITY | + SD_SWITCH_1_8V_CAPACITY); + if (errorstate != HAL_SD_ERROR_NONE) + { + return HAL_SD_ERROR_UNSUPPORTED_FEATURE; + } + + /* Get command response */ + response = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + + /* Get operating voltage*/ + validvoltage = (((response >> 31U) == 1U) ? 1U : 0U); + + count++; + } + + if (count >= SDMMC_MAX_VOLT_TRIAL) + { + return HAL_SD_ERROR_INVALID_VOLTRANGE; + } + + /* Set default card type */ + hsd->SdCard.CardType = CARD_SDSC; + + if ((response & SDMMC_HIGH_CAPACITY) == SDMMC_HIGH_CAPACITY) + { + hsd->SdCard.CardType = CARD_SDHC_SDXC; +#if (USE_SD_TRANSCEIVER != 0U) + if (hsd->Init.TranceiverPresent == SDMMC_TRANSCEIVER_PRESENT) + { + if ((response & SD_SWITCH_1_8V_CAPACITY) == SD_SWITCH_1_8V_CAPACITY) + { + hsd->SdCard.CardSpeed = CARD_ULTRA_HIGH_SPEED; + + /* Start switching procedue */ + hsd->Instance->POWER |= SDMMC_POWER_VSWITCHEN; + + /* Send CMD11 to switch 1.8V mode */ + errorstate = SDMMC_CmdVoltageSwitch(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Check to CKSTOP */ + while ((hsd->Instance->STA & SDMMC_FLAG_CKSTOP) != SDMMC_FLAG_CKSTOP) + { + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + return HAL_SD_ERROR_TIMEOUT; + } + } + + /* Clear CKSTOP Flag */ + hsd->Instance->ICR = SDMMC_FLAG_CKSTOP; + + /* Check to BusyD0 */ + if ((hsd->Instance->STA & SDMMC_FLAG_BUSYD0) != SDMMC_FLAG_BUSYD0) + { + /* Error when activate Voltage Switch in SDMMC Peripheral */ + return SDMMC_ERROR_UNSUPPORTED_FEATURE; + } + else + { + /* Enable Transceiver Switch PIN */ +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->DriveTransceiver_1_8V_Callback(SET); +#else + HAL_SD_DriveTransceiver_1_8V_Callback(SET); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ + + /* Switch ready */ + hsd->Instance->POWER |= SDMMC_POWER_VSWITCH; + + /* Check VSWEND Flag */ + while ((hsd->Instance->STA & SDMMC_FLAG_VSWEND) != SDMMC_FLAG_VSWEND) + { + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + return HAL_SD_ERROR_TIMEOUT; + } + } + + /* Clear VSWEND Flag */ + hsd->Instance->ICR = SDMMC_FLAG_VSWEND; + + /* Check BusyD0 status */ + if ((hsd->Instance->STA & SDMMC_FLAG_BUSYD0) == SDMMC_FLAG_BUSYD0) + { + /* Error when enabling 1.8V mode */ + return HAL_SD_ERROR_INVALID_VOLTRANGE; + } + /* Switch to 1.8V OK */ + + /* Disable VSWITCH FLAG from SDMMC Peripheral */ + hsd->Instance->POWER = 0x13U; + + /* Clean Status flags */ + hsd->Instance->ICR = 0xFFFFFFFFU; + } + } + } +#endif /* USE_SD_TRANSCEIVER */ + } + + return HAL_SD_ERROR_NONE; +} + +/** + * @brief Turns the SDMMC output signals off. + * @param hsd: Pointer to SD handle + * @retval None + */ +static void SD_PowerOFF(SD_HandleTypeDef *hsd) +{ + /* Set Power State to OFF */ + (void)SDMMC_PowerState_OFF(hsd->Instance); +} + +/** + * @brief Send Status info command. + * @param hsd: pointer to SD handle + * @param pSDstatus: Pointer to the buffer that will contain the SD card status + * SD Status register) + * @retval error state + */ +static uint32_t SD_SendSDStatus(SD_HandleTypeDef *hsd, uint32_t *pSDstatus) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t tickstart = HAL_GetTick(); + uint32_t count; + uint32_t *pData = pSDstatus; + + /* Check SD response */ + if ((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + { + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + } + + /* Set block size for card if it is not equal to current block size for card */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_NONE; + return errorstate; + } + + /* Send CMD55 */ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_NONE; + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = 64U; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_ENABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + + /* Send ACMD13 (SD_APP_STAUS) with argument as card's RCA */ + errorstate = SDMMC_CmdStatusRegister(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + hsd->ErrorCode |= HAL_SD_ERROR_NONE; + return errorstate; + } + + /* Get status data */ + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND)) + { + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + { + for (count = 0U; count < 8U; count++) + { + *pData = SDMMC_ReadFIFO(hsd->Instance); + pData++; + } + } + + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + { + return HAL_SD_ERROR_DATA_TIMEOUT; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + { + return HAL_SD_ERROR_DATA_CRC_FAIL; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + return HAL_SD_ERROR_RX_OVERRUN; + } + else + { + /* Nothing to do */ + } + + while ((__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DPSMACT))) + { + *pData = SDMMC_ReadFIFO(hsd->Instance); + pData++; + + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + return HAL_SD_ERROR_TIMEOUT; + } + } + + /* Clear all the static status flags*/ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + return HAL_SD_ERROR_NONE; +} + +/** + * @brief Returns the current card's status. + * @param hsd: Pointer to SD handle + * @param pCardStatus: pointer to the buffer that will contain the SD card + * status (Card Status register) + * @retval error state + */ +static uint32_t SD_SendStatus(SD_HandleTypeDef *hsd, uint32_t *pCardStatus) +{ + uint32_t errorstate; + + if (pCardStatus == NULL) + { + return HAL_SD_ERROR_PARAM; + } + + /* Send Status command */ + errorstate = SDMMC_CmdSendStatus(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Get SD card status */ + *pCardStatus = SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1); + + return HAL_SD_ERROR_NONE; +} + +/** + * @brief Enables the SDMMC wide bus mode. + * @param hsd: pointer to SD handle + * @retval error state + */ +static uint32_t SD_WideBus_Enable(SD_HandleTypeDef *hsd) +{ + uint32_t scr[2U] = {0UL, 0UL}; + uint32_t errorstate; + + if ((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + { + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + } + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, scr); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* If requested card supports wide bus operation */ + if ((scr[1U] & SDMMC_WIDE_BUS_SUPPORT) != SDMMC_ALLZERO) + { + /* Send CMD55 APP_CMD with argument as card's RCA.*/ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Send ACMD6 APP_CMD with argument as 2 for wide bus mode */ + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 2U); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + return HAL_SD_ERROR_NONE; + } + else + { + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } +} + +/** + * @brief Disables the SDMMC wide bus mode. + * @param hsd: Pointer to SD handle + * @retval error state + */ +static uint32_t SD_WideBus_Disable(SD_HandleTypeDef *hsd) +{ + uint32_t scr[2U] = {0UL, 0UL}; + uint32_t errorstate; + + if ((SDMMC_GetResponse(hsd->Instance, SDMMC_RESP1) & SDMMC_CARD_LOCKED) == SDMMC_CARD_LOCKED) + { + return HAL_SD_ERROR_LOCK_UNLOCK_FAILED; + } + + /* Get SCR Register */ + errorstate = SD_FindSCR(hsd, scr); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* If requested card supports 1 bit mode operation */ + if ((scr[1U] & SDMMC_SINGLE_BUS_SUPPORT) != SDMMC_ALLZERO) + { + /* Send CMD55 APP_CMD with argument as card's RCA */ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)(hsd->SdCard.RelCardAdd << 16U)); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Send ACMD6 APP_CMD with argument as 0 for single bus mode */ + errorstate = SDMMC_CmdBusWidth(hsd->Instance, 0U); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + return HAL_SD_ERROR_NONE; + } + else + { + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } +} + + +/** + * @brief Finds the SD card SCR register value. + * @param hsd: Pointer to SD handle + * @param pSCR: pointer to the buffer that will contain the SCR value + * @retval error state + */ +static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR) +{ + SDMMC_DataInitTypeDef config; + uint32_t errorstate; + uint32_t tickstart = HAL_GetTick(); + uint32_t index = 0U; + uint32_t tempscr[2U] = {0UL, 0UL}; + uint32_t *scr = pSCR; + + /* Set Block Size To 8 Bytes */ + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Send CMD55 APP_CMD with argument as card's RCA */ + errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)((hsd->SdCard.RelCardAdd) << 16U)); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + config.DataTimeOut = SDMMC_DATATIMEOUT; + config.DataLength = 8U; + config.DataBlockSize = SDMMC_DATABLOCK_SIZE_8B; + config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + config.DPSM = SDMMC_DPSM_ENABLE; + (void)SDMMC_ConfigData(hsd->Instance, &config); + + /* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */ + errorstate = SDMMC_CmdSendSCR(hsd->Instance); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | + SDMMC_FLAG_DATAEND)) + { + if ((!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOE)) && (index == 0U)) + { + tempscr[0] = SDMMC_ReadFIFO(hsd->Instance); + tempscr[1] = SDMMC_ReadFIFO(hsd->Instance); + index++; + } + + + if ((HAL_GetTick() - tickstart) >= SDMMC_SWDATATIMEOUT) + { + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + + return HAL_SD_ERROR_DATA_TIMEOUT; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + + return HAL_SD_ERROR_DATA_CRC_FAIL; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + + return HAL_SD_ERROR_RX_OVERRUN; + } + else + { + /* No error flag set */ + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + *scr = (((tempscr[1] & SDMMC_0TO7BITS) << 24U) | ((tempscr[1] & SDMMC_8TO15BITS) << 8U) | \ + ((tempscr[1] & SDMMC_16TO23BITS) >> 8U) | ((tempscr[1] & SDMMC_24TO31BITS) >> 24U)); + scr++; + *scr = (((tempscr[0] & SDMMC_0TO7BITS) << 24U) | ((tempscr[0] & SDMMC_8TO15BITS) << 8U) | \ + ((tempscr[0] & SDMMC_16TO23BITS) >> 8U) | ((tempscr[0] & SDMMC_24TO31BITS) >> 24U)); + + } + + return HAL_SD_ERROR_NONE; +} + +/** + * @brief Wrap up reading in non-blocking mode. + * @param hsd: pointer to a SD_HandleTypeDef structure that contains + * the configuration information. + * @retval None + */ +static void SD_Read_IT(SD_HandleTypeDef *hsd) +{ + uint32_t count; + uint32_t data; + uint8_t *tmp; + + tmp = hsd->pRxBuffPtr; + + if (hsd->RxXferSize >= SDMMC_FIFO_SIZE) + { + /* Read data from SDMMC Rx FIFO */ + for (count = 0U; count < (SDMMC_FIFO_SIZE / 4U); count++) + { + data = SDMMC_ReadFIFO(hsd->Instance); + *tmp = (uint8_t)(data & 0xFFU); + tmp++; + *tmp = (uint8_t)((data >> 8U) & 0xFFU); + tmp++; + *tmp = (uint8_t)((data >> 16U) & 0xFFU); + tmp++; + *tmp = (uint8_t)((data >> 24U) & 0xFFU); + tmp++; + } + + hsd->pRxBuffPtr = tmp; + hsd->RxXferSize -= SDMMC_FIFO_SIZE; + } +} + +/** + * @brief Wrap up writing in non-blocking mode. + * @param hsd: pointer to a SD_HandleTypeDef structure that contains + * the configuration information. + * @retval None + */ +static void SD_Write_IT(SD_HandleTypeDef *hsd) +{ + uint32_t count; + uint32_t data; + const uint8_t *tmp; + + tmp = hsd->pTxBuffPtr; + + if (hsd->TxXferSize >= SDMMC_FIFO_SIZE) + { + /* Write data to SDMMC Tx FIFO */ + for (count = 0U; count < (SDMMC_FIFO_SIZE / 4U); count++) + { + data = (uint32_t)(*tmp); + tmp++; + data |= ((uint32_t)(*tmp) << 8U); + tmp++; + data |= ((uint32_t)(*tmp) << 16U); + tmp++; + data |= ((uint32_t)(*tmp) << 24U); + tmp++; + (void)SDMMC_WriteFIFO(hsd->Instance, &data); + } + + hsd->pTxBuffPtr = tmp; + hsd->TxXferSize -= SDMMC_FIFO_SIZE; + } +} + +/** + * @brief Switches the SD card to High Speed mode. + * This API must be used after "Transfer State" + * @note This operation should be followed by the configuration + * of PLL to have SDMMCCK clock between 25 and 50 MHz + * @param hsd: SD handle + * @param SwitchSpeedMode: SD speed mode( SDMMC_SDR12_SWITCH_PATTERN, SDMMC_SDR25_SWITCH_PATTERN) + * @retval SD Card error state + */ +uint32_t SD_SwitchSpeed(SD_HandleTypeDef *hsd, uint32_t SwitchSpeedMode) +{ + uint32_t errorstate = HAL_SD_ERROR_NONE; + SDMMC_DataInitTypeDef sdmmc_datainitstructure; + uint32_t SD_hs[16] = {0}; + uint32_t count; + uint32_t loop = 0 ; + uint32_t Timeout = HAL_GetTick(); + + if (hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + { + /* Standard Speed Card <= 12.5Mhz */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if (hsd->SdCard.CardSpeed >= CARD_HIGH_SPEED) + { + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 64U; + sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + + (void)SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure); + + + errorstate = SDMMC_CmdSwitch(hsd->Instance, SwitchSpeedMode); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | + SDMMC_FLAG_DATAEND)) + { + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + { + for (count = 0U; count < 8U; count++) + { + SD_hs[(8U * loop) + count] = SDMMC_ReadFIFO(hsd->Instance); + } + loop ++; + } + + if ((HAL_GetTick() - Timeout) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + + errorstate = SDMMC_ERROR_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + + errorstate = SDMMC_ERROR_RX_OVERRUN; + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + /* Test if the switch mode HS is ok */ + if ((((uint8_t *)SD_hs)[13] & 2U) != 2U) + { + errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE; + } + + } + + return errorstate; +} + +#if (USE_SD_TRANSCEIVER != 0U) +/** + * @brief Switches the SD card to Ultra High Speed mode. + * This API must be used after "Transfer State" + * @note This operation should be followed by the configuration + * of PLL to have SDMMCCK clock between 50 and 120 MHz + * @param hsd: SD handle + * @param UltraHighSpeedMode: SD speed mode( SDMMC_SDR50_SWITCH_PATTERN, SDMMC_SDR104_SWITCH_PATTERN) + * @retval SD Card error state + */ +static uint32_t SD_UltraHighSpeed(SD_HandleTypeDef *hsd, uint32_t UltraHighSpeedMode) +{ + uint32_t errorstate = HAL_SD_ERROR_NONE; + SDMMC_DataInitTypeDef sdmmc_datainitstructure; + uint32_t SD_hs[16] = {0}; + uint32_t count; + uint32_t loop = 0 ; + uint32_t Timeout = HAL_GetTick(); + + if (hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + { + /* Standard Speed Card <= 12.5Mhz */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if (hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) + { + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 64U; + sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + + if (SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + { + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + } + + errorstate = SDMMC_CmdSwitch(hsd->Instance, UltraHighSpeedMode); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | + SDMMC_FLAG_DATAEND)) + { + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + { + for (count = 0U; count < 8U; count++) + { + SD_hs[(8U * loop) + count] = SDMMC_ReadFIFO(hsd->Instance); + } + loop ++; + } + + if ((HAL_GetTick() - Timeout) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + + errorstate = SDMMC_ERROR_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + + errorstate = SDMMC_ERROR_RX_OVERRUN; + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + /* Test if the switch mode HS is ok */ + if ((((uint8_t *)SD_hs)[13] & 2U) != 2U) + { + errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE; + } + else + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->DriveTransceiver_1_8V_Callback(SET); +#else + HAL_SD_DriveTransceiver_1_8V_Callback(SET); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ +#if defined (DLYB_SDMMC1) || defined (DLYB_SDMMC2) + /* Enable DelayBlock Peripheral */ + /* SDMMC_FB_CLK tuned feedback clock selected as receive clock, for SDR104 */ + MODIFY_REG(hsd->Instance->CLKCR, SDMMC_CLKCR_SELCLKRX, SDMMC_CLKCR_SELCLKRX_1); + LL_DLYB_Enable(SD_GET_DLYB_INSTANCE(hsd->Instance)); +#endif /* (DLYB_SDMMC1) || (DLYB_SDMMC2) */ + } + } + + return errorstate; +} + +/** + * @brief Switches the SD card to Double Data Rate (DDR) mode. + * This API must be used after "Transfer State" + * @note This operation should be followed by the configuration + * of PLL to have SDMMCCK clock less than 50MHz + * @param hsd: SD handle + * @retval SD Card error state + */ +static uint32_t SD_DDR_Mode(SD_HandleTypeDef *hsd) +{ + uint32_t errorstate = HAL_SD_ERROR_NONE; + SDMMC_DataInitTypeDef sdmmc_datainitstructure; + uint32_t SD_hs[16] = {0}; + uint32_t count; + uint32_t loop = 0 ; + uint32_t Timeout = HAL_GetTick(); + + if (hsd->SdCard.CardSpeed == CARD_NORMAL_SPEED) + { + /* Standard Speed Card <= 12.5Mhz */ + return HAL_SD_ERROR_REQUEST_NOT_APPLICABLE; + } + + if (hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) + { + /* Initialize the Data control register */ + hsd->Instance->DCTRL = 0; + errorstate = SDMMC_CmdBlockLength(hsd->Instance, 64U); + + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + /* Configure the SD DPSM (Data Path State Machine) */ + sdmmc_datainitstructure.DataTimeOut = SDMMC_DATATIMEOUT; + sdmmc_datainitstructure.DataLength = 64U; + sdmmc_datainitstructure.DataBlockSize = SDMMC_DATABLOCK_SIZE_64B ; + sdmmc_datainitstructure.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC; + sdmmc_datainitstructure.TransferMode = SDMMC_TRANSFER_MODE_BLOCK; + sdmmc_datainitstructure.DPSM = SDMMC_DPSM_ENABLE; + + if (SDMMC_ConfigData(hsd->Instance, &sdmmc_datainitstructure) != HAL_OK) + { + return (HAL_SD_ERROR_GENERAL_UNKNOWN_ERR); + } + + errorstate = SDMMC_CmdSwitch(hsd->Instance, SDMMC_DDR50_SWITCH_PATTERN); + if (errorstate != HAL_SD_ERROR_NONE) + { + return errorstate; + } + + while (!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND | + SDMMC_FLAG_DATAEND)) + { + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF)) + { + for (count = 0U; count < 8U; count++) + { + SD_hs[(8U * loop) + count] = SDMMC_ReadFIFO(hsd->Instance); + } + loop ++; + } + + if ((HAL_GetTick() - Timeout) >= SDMMC_SWDATATIMEOUT) + { + hsd->ErrorCode = HAL_SD_ERROR_TIMEOUT; + hsd->State = HAL_SD_STATE_READY; + return HAL_SD_ERROR_TIMEOUT; + } + } + + if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT); + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL); + + errorstate = SDMMC_ERROR_DATA_CRC_FAIL; + + return errorstate; + } + else if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR)) + { + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR); + + errorstate = SDMMC_ERROR_RX_OVERRUN; + + return errorstate; + } + else + { + /* No error flag set */ + } + + /* Clear all the static flags */ + __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS); + + /* Test if the switch mode is ok */ + if ((((uint8_t *)SD_hs)[13] & 2U) != 2U) + { + errorstate = SDMMC_ERROR_UNSUPPORTED_FEATURE; + } + else + { +#if defined (USE_HAL_SD_REGISTER_CALLBACKS) && (USE_HAL_SD_REGISTER_CALLBACKS == 1U) + hsd->DriveTransceiver_1_8V_Callback(SET); +#else + HAL_SD_DriveTransceiver_1_8V_Callback(SET); +#endif /* USE_HAL_SD_REGISTER_CALLBACKS */ +#if defined (DLYB_SDMMC1) || defined (DLYB_SDMMC2) + /* Enable DelayBlock Peripheral */ + /* SDMMC_CKin feedback clock selected as receive clock, for DDR50 */ + MODIFY_REG(hsd->Instance->CLKCR, SDMMC_CLKCR_SELCLKRX, SDMMC_CLKCR_SELCLKRX_0); + LL_DLYB_Enable(SD_GET_DLYB_INSTANCE(hsd->Instance)); +#endif /* (DLYB_SDMMC1) || (DLYB_SDMMC2) */ + } + } + + return errorstate; +} + +#endif /* USE_SD_TRANSCEIVER */ + +/** + * @brief Read DMA Linked list node Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SDEx_Read_DMALnkLstBufCpltCallback(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SDEx_Read_DMALnkLstBufCpltCallback can be implemented in the user file + */ +} +/** + * @brief Read DMA Linked list node Transfer completed callbacks + * @param hsd: SD handle + * @retval None + */ +__weak void HAL_SDEx_Write_DMALnkLstBufCpltCallback(SD_HandleTypeDef *hsd) +{ + /* Prevent unused argument(s) compilation warning */ + UNUSED(hsd); + + /* NOTE : This function should not be modified, when the callback is needed, + the HAL_SDEx_Write_DMALnkLstBufCpltCallback can be implemented in the user file + */ +} + +/** + * @} + */ + +#endif /* HAL_SD_MODULE_ENABLED */ +#endif /* SDMMC1 || SDMMC2 */ + +/** + * @} + */ + +/** + * @} + */ + +// clang-format on diff --git a/core/embed/trezorhal/stm32u5/supervise.c b/core/embed/trezorhal/stm32u5/supervise.c new file mode 120000 index 00000000000..385e9d43cad --- /dev/null +++ b/core/embed/trezorhal/stm32u5/supervise.c @@ -0,0 +1 @@ +../stm32f4/supervise.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/supervise.h b/core/embed/trezorhal/stm32u5/supervise.h new file mode 120000 index 00000000000..f519770f494 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/supervise.h @@ -0,0 +1 @@ +../stm32f4/supervise.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systemview.h b/core/embed/trezorhal/stm32u5/systemview.h new file mode 120000 index 00000000000..fda5c909e71 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systemview.h @@ -0,0 +1 @@ +../../firmware/systemview.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systick.c b/core/embed/trezorhal/stm32u5/systick.c new file mode 120000 index 00000000000..1a5e42f1094 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systick.c @@ -0,0 +1 @@ +../stm32f4/systick.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/systick.h b/core/embed/trezorhal/stm32u5/systick.h new file mode 120000 index 00000000000..1d1261d2cb5 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/systick.h @@ -0,0 +1 @@ +../stm32f4/systick.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/tamper.c b/core/embed/trezorhal/stm32u5/tamper.c new file mode 100644 index 00000000000..68bee8da4a0 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/tamper.c @@ -0,0 +1,273 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include +#include +#include +#include STM32_HAL_H + +// Fixes a typo in CMSIS Device library for STM32U5 +#undef TAMP_CR3_ITAMP7NOER_Msk +#undef TAMP_CR3_ITAMP7NOER +#define TAMP_CR3_ITAMP7NOER_Msk (0x1UL << TAMP_CR3_ITAMP7NOER_Pos) +#define TAMP_CR3_ITAMP7NOER TAMP_CR3_ITAMP7NOER_Msk + +/* + * This function replaces calls to universal, but flash-wasting + * functions HAL_RCC_OscConfig and HAL_RCCEx_PeriphCLKConfig. + * + * This is the configuration before the optimization: + * osc_init_def.OscillatorType = RCC_OSCILLATORTYPE_LSI; + * osc_init_def.LSIState = RCC_LSI_ON; + * HAL_RCC_OscConfig(&osc_init_def); + * + * clk_init_def.PeriphClockSelection = RCC_PERIPHCLK_RTC; + * clk_init_def.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; + * HAL_RCCEx_PeriphCLKConfig(&clk_init_def); + */ +HAL_StatusTypeDef lsi_init(void) { + uint32_t tickstart = 0U; + + FlagStatus pwrclkchanged = RESET; + + /* Update LSI configuration in Backup Domain control register */ + /* Requires to enable write access to Backup Domain of necessary */ + if (__HAL_RCC_PWR_IS_CLK_DISABLED()) { + __HAL_RCC_PWR_CLK_ENABLE(); + pwrclkchanged = SET; + } + + if (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) { + /* Enable write access to Backup domain */ + SET_BIT(PWR->DBPR, PWR_DBPR_DBP); + + /* Wait for Backup domain Write protection disable */ + tickstart = HAL_GetTick(); + + while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) { + if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) { + /* Restore clock configuration if changed */ + if (pwrclkchanged == SET) { + __HAL_RCC_PWR_CLK_DISABLE(); + } + return HAL_TIMEOUT; + } + } + } + + uint32_t bdcr_temp = RCC->BDCR; + + if (RCC_LSI_DIV1 != (bdcr_temp & RCC_BDCR_LSIPREDIV)) { + if (((bdcr_temp & RCC_BDCR_LSIRDY) == RCC_BDCR_LSIRDY) && + ((bdcr_temp & RCC_BDCR_LSION) != RCC_BDCR_LSION)) { + /* If LSIRDY is set while LSION is not enabled, LSIPREDIV can't be updated + */ + /* The LSIPREDIV cannot be changed if the LSI is used by the IWDG or by + * the RTC */ + /* Restore clock configuration if changed */ + if (pwrclkchanged == SET) { + __HAL_RCC_PWR_CLK_DISABLE(); + } + return HAL_ERROR; + } + + /* Turn off LSI before changing RCC_BDCR_LSIPREDIV */ + if ((bdcr_temp & RCC_BDCR_LSION) == RCC_BDCR_LSION) { + __HAL_RCC_LSI_DISABLE(); + + tickstart = HAL_GetTick(); + + /* Wait till LSI is disabled */ + while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) != 0U) + ; + } + + /* Set LSI division factor */ + MODIFY_REG(RCC->BDCR, RCC_BDCR_LSIPREDIV, 0); + } + + /* Enable the Internal Low Speed oscillator (LSI) */ + __HAL_RCC_LSI_ENABLE(); + + /* Wait till LSI is ready */ + while (READ_BIT(RCC->BDCR, RCC_BDCR_LSIRDY) == 0U) + ; + + /* Check for RTC Parameters used to output RTCCLK */ + assert_param(IS_RCC_RTCCLKSOURCE(pPeriphClkInit->RTCClockSelection)); + /* Enable Power Clock */ + if (__HAL_RCC_PWR_IS_CLK_DISABLED()) { + __HAL_RCC_PWR_CLK_ENABLE(); + pwrclkchanged = SET; + } + /* Enable write access to Backup domain */ + SET_BIT(PWR->DBPR, PWR_DBPR_DBP); + + /* Wait for Backup domain Write protection disable */ + tickstart = HAL_GetTick(); + + while (HAL_IS_BIT_CLR(PWR->DBPR, PWR_DBPR_DBP)) { + if ((HAL_GetTick() - tickstart) > RCC_DBP_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + /* Reset the Backup domain only if the RTC Clock source selection is modified + * from default */ + bdcr_temp = READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL); + + if ((bdcr_temp != RCC_RTCCLKSOURCE_NO_CLK) && + (bdcr_temp != RCC_RTCCLKSOURCE_LSI)) { + /* Store the content of BDCR register before the reset of Backup Domain */ + bdcr_temp = READ_BIT(RCC->BDCR, ~(RCC_BDCR_RTCSEL)); + /* RTC Clock selection can be changed only if the Backup Domain is reset */ + __HAL_RCC_BACKUPRESET_FORCE(); + __HAL_RCC_BACKUPRESET_RELEASE(); + /* Restore the Content of BDCR register */ + RCC->BDCR = bdcr_temp; + } + + /* Wait for LSE reactivation if LSE was enable prior to Backup Domain reset */ + if (HAL_IS_BIT_SET(bdcr_temp, RCC_BDCR_LSEON)) { + /* Get Start Tick*/ + tickstart = HAL_GetTick(); + + /* Wait till LSE is ready */ + while (READ_BIT(RCC->BDCR, RCC_BDCR_LSERDY) == 0U) { + if ((HAL_GetTick() - tickstart) > RCC_LSE_TIMEOUT_VALUE) { + return HAL_TIMEOUT; + } + } + } + + /* Apply new RTC clock source selection */ + __HAL_RCC_RTC_CONFIG(RCC_PERIPHCLK_RTC); + + /* Restore clock configuration if changed */ + if (pwrclkchanged == SET) { + __HAL_RCC_PWR_CLK_DISABLE(); + } + return HAL_OK; +} + +void tamper_init(void) { + // Enable LSI clock + lsi_init(); + + // Enable RTC peripheral (tampers are part of it) + __HAL_RCC_RTC_ENABLE(); + __HAL_RCC_RTCAPB_CLK_ENABLE(); + + // Clear all pending interrupts + // They may be some as RTC/TAMP peripherals resides inside the + // backup voltage domain + TAMP->SCR = TAMP_SCR_CTAMP2F | TAMP_SCR_CITAMP1F | TAMP_SCR_CITAMP2F | + TAMP_SCR_CITAMP3F | TAMP_SCR_CITAMP5F | TAMP_SCR_CITAMP6F | + TAMP_SCR_CITAMP7F | TAMP_SCR_CITAMP8F | TAMP_SCR_CITAMP9F | + TAMP_SCR_CITAMP11F | TAMP_SCR_CITAMP12F | TAMP_SCR_CITAMP13F; + + NVIC_ClearPendingIRQ(TAMP_IRQn); + + // Enable battery and power monitoring (!@# rework it) + RCC->AHB3ENR |= RCC_AHB3ENR_PWREN; + // HAL_PWR_EnableBkUpAccess(); + PWR->BDCR1 |= PWR_BDCR1_MONEN; + // HAL_PWR_DisableBkUpAccess(); + + // Enable all internal tampers (4th and 10th are intentionally skipped) + // We select all of them despite some of them are never triggered + TAMP->CR1 = + TAMP_CR1_ITAMP1E | // backup domain voltage monitoring + TAMP_CR1_ITAMP2E | // temperature monitoring + TAMP_CR1_ITAMP3E | // LSE monitoring (LSECSS) + TAMP_CR1_ITAMP5E | // RTC calendar overflow + TAMP_CR1_ITAMP6E | // JTAG/SWD access when RDP > 0 + TAMP_CR1_ITAMP7E | // ADC4 analog watchdog monitoring 1 + TAMP_CR1_ITAMP8E | // Monotonic counter 1 overflow + TAMP_CR1_ITAMP9E | // Crypto periherals fault (SAES, AES, PKA, TRNG) + TAMP_CR1_ITAMP11E | // IWDG reset when tamper flag is set + TAMP_CR1_ITAMP12E | // ADC4 analog watchdog monitoring 2 + TAMP_CR1_ITAMP13E; // ADC4 analog watchdog monitoring 3 + + // Switch all internal tampers to the "confirmed" mode + // => all secrets all deleted when any tamper event is triggered + TAMP->CR3 = 0; + + // Setup external tampers + // TAMP_IN2 active low, "confirmed" mode + TAMP->CR2 = 0; + // TAMP_CR2_TAMP2TRG; + + // Set external tamper input filter + TAMP->FLTCR = + // TAMP_FLTCR_TAMPPUDIS | // disable pre-charge of TAMP_INx pins + (3 << TAMP_FLTCR_TAMPPRCH_Pos) | // pre-charge 8 RTCCLK cycles + (2 << TAMP_FLTCR_TAMPFLT_Pos) | // activated after 4 same samples + (7 << TAMP_FLTCR_TAMPFREQ_Pos); // sampling period RTCCLK / 256 (128Hz) + + // Enable all interrupts for all internal tampers + TAMP->IER = TAMP_IER_TAMP2IE | TAMP_IER_ITAMP1IE | TAMP_IER_ITAMP2IE | + TAMP_IER_ITAMP3IE | TAMP_IER_ITAMP5IE | TAMP_IER_ITAMP6IE | + TAMP_IER_ITAMP7IE | TAMP_IER_ITAMP8IE | TAMP_IER_ITAMP9IE | + TAMP_IER_ITAMP11IE | TAMP_IER_ITAMP12IE | TAMP_IER_ITAMP13IE; + + // Enable TAMP interrupt at NVIC controller + NVIC_SetPriority(TAMP_IRQn, IRQ_PRI_TAMP); + NVIC_EnableIRQ(TAMP_IRQn); +} + +// Interrupt handle for all tamper events +// It displays an error message +void TAMP_IRQHandler(void) { + uint32_t sr = TAMP->SR; + TAMP->SCR = sr; + +#ifdef BOARDLOADER + error_shutdown("INTERNAL TAMPER", ""); +#else + const char* reason = "UNKNOWN"; + if (sr & TAMP_SR_TAMP1F) { + reason = "INPUT1"; + } else if (sr & TAMP_SR_TAMP2F) { + reason = "INPUT2"; + } else if (sr & TAMP_SR_ITAMP1F) { + reason = "VOLTAGE"; + } else if (sr & TAMP_SR_ITAMP2F) { + reason = "TEMPERATURE"; + } else if (sr & TAMP_SR_ITAMP3F) { + reason = "LSE CLOCK"; + } else if (sr & TAMP_SR_ITAMP5F) { + reason = "RTC OVERFLOW"; + } else if (sr & TAMP_SR_ITAMP6F) { + reason = "SWD ACCESS"; + } else if (sr & TAMP_SR_ITAMP7F) { + reason = "ANALOG WDG1"; + } else if (sr & TAMP_SR_ITAMP8F) { + reason = "MONO COUNTER"; + } else if (sr & TAMP_SR_ITAMP9F) { + reason = "CRYPTO ERROR"; + } else if (sr & TAMP_SR_ITAMP11F) { + reason = "IWDG"; + } else if (sr & TAMP_SR_ITAMP12F) { + reason = "ANALOG WDG2"; + } else if (sr & TAMP_SR_ITAMP13F) { + reason = "ANALOG WDG3"; + } + error_shutdown("INTERNAL TAMPER", reason); +#endif +} diff --git a/core/embed/trezorhal/stm32u5/touch/ft6x36.c b/core/embed/trezorhal/stm32u5/touch/ft6x36.c new file mode 120000 index 00000000000..68b33fbb6ac --- /dev/null +++ b/core/embed/trezorhal/stm32u5/touch/ft6x36.c @@ -0,0 +1 @@ +../../stm32f4/touch/ft6x36.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/touch/ft6x36.h b/core/embed/trezorhal/stm32u5/touch/ft6x36.h new file mode 120000 index 00000000000..2c609d19bfc --- /dev/null +++ b/core/embed/trezorhal/stm32u5/touch/ft6x36.h @@ -0,0 +1 @@ +../../stm32f4/touch/ft6x36.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/touch/sitronix.c b/core/embed/trezorhal/stm32u5/touch/sitronix.c new file mode 100644 index 00000000000..a9f4d0a4375 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/touch/sitronix.c @@ -0,0 +1,1216 @@ +#include STM32_HAL_H +#include TREZOR_BOARD + +#include "i2c.h" + +/** @addtogroup STM32U5x9J_DISCOVERY + * @{ + */ + +/** @addtogroup STM32U5x9J_DISCOVERY_BUS + * @{ + */ +/** @defgroup STM32U5x9J_DISCOVERY_BUS_Exported_Types BUS Exported Types + * @{ + */ +/* Common Error codes */ +#define BSP_ERROR_NONE 0 +#define BSP_ERROR_NO_INIT -1 +#define BSP_ERROR_WRONG_PARAM -2 +#define BSP_ERROR_BUSY -3 +#define BSP_ERROR_PERIPH_FAILURE -4 +#define BSP_ERROR_COMPONENT_FAILURE -5 +#define BSP_ERROR_UNKNOWN_FAILURE -6 +#define BSP_ERROR_UNKNOWN_COMPONENT -7 +#define BSP_ERROR_BUS_FAILURE -8 +#define BSP_ERROR_CLOCK_FAILURE -9 +#define BSP_ERROR_MSP_FAILURE -10 +#define BSP_ERROR_FEATURE_NOT_SUPPORTED -11 + +/* BSP OSPI error codes */ +#define BSP_ERROR_OSPI_SUSPENDED -20 +#define BSP_ERROR_OSPI_MMP_UNLOCK_FAILURE -21 +#define BSP_ERROR_OSPI_MMP_LOCK_FAILURE -22 + +/* BSP HSPI error codes */ +#define BSP_ERROR_HSPI_MMP_UNLOCK_FAILURE -31 +#define BSP_ERROR_HSPI_MMP_LOCK_FAILURE -32 + +/* BSP BUS error codes */ +#define BSP_ERROR_BUS_TRANSACTION_FAILURE -100 +#define BSP_ERROR_BUS_ARBITRATION_LOSS -101 +#define BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE -102 +#define BSP_ERROR_BUS_PROTOCOL_FAILURE -103 + +#define BSP_ERROR_BUS_MODE_FAULT -104 +#define BSP_ERROR_BUS_FRAME_ERROR -105 +#define BSP_ERROR_BUS_CRC_ERROR -106 +#define BSP_ERROR_BUS_DMA_FAILURE -107 + +/* TS I2C address */ +#define TS_I2C_ADDRESS 0xE0U + +/******************************************************************************* + * Function Name : sitronix_read_reg + * Description : Generic Reading function. It must be full-filled with either + * I2C or SPI reading functions + * Input : Register Address, length of buffer + * Output : pdata Read + *******************************************************************************/ +int32_t sitronix_read_reg(uint8_t reg, uint8_t *pdata, uint16_t length) { + return i2c_mem_read(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, reg, length, pdata, + length, 1000); +} + +/******************************************************************************* + * Function Name : sitronix_write_reg + * Description : Generic Writing function. It must be full-filled with either + * I2C or SPI writing function + * Input : Register Address, pdata to be written, length of buffer + * Output : None + *******************************************************************************/ +int32_t sitronix_write_reg(uint8_t reg, uint8_t *pdata, uint16_t length) { + return i2c_mem_write(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, reg, length, pdata, + length, 1000); +} + +/******************************************************************************* + * Function Name : sitronix_read_data + * Description : Generic Reading function. It must be full-filled with either + * I2C or SPI reading functions + * Input : Register Address, length of buffer + * Output : pdata Read + *******************************************************************************/ +int32_t sitronix_read_data(uint8_t *pdata, uint16_t length) { + return i2c_receive(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, pdata, length, 1000); +} + +/* Includes ------------------------------------------------------------------*/ +/* Macros --------------------------------------------------------------------*/ +/* Exported types ------------------------------------------------------------*/ +/* Exported constants --------------------------------------------------------*/ +#define SITRONIX_MAX_X_LENGTH 480U +#define SITRONIX_MAX_Y_LENGTH 480U + +/** @defgroup SITRONIX_Exported_Constants SITRONIX Exported Constants + * @{ + */ +#define SITRONIX_OK (0) +#define SITRONIX_ERROR (-1) + +/* Max detectable simultaneous touches */ +#define SITRONIX_MAX_DETECTABLE_TOUCH 10U + +/* Touch FT6XX6 IDs */ +#define SITRONIX_ID 0x02U + +/* Values Pn_XH and Pn_YH related */ +#define SITRONIX_TOUCH_EVT_FLAG_PRESS_DOWN 0x20U +#define SITRONIX_TOUCH_EVT_FLAG_LIFT_UP 0x60U +#define SITRONIX_TOUCH_EVT_FLAG_CONTACT 0x80U +#define SITRONIX_TOUCH_EVT_FLAG_NO_EVENT 0x00U +#define SITRONIX_TOUCH_POS_MSB_MASK 0x07U +#define SITRONIX_TOUCH_POS_LSB_MASK 0x70U + +/* Point 1 registers */ +#define SITRONIX_P1_XH_REG 0x09U +#define SITRONIX_P1_XL_REG 0x0AU +#define SITRONIX_P1_YH_REG 0x0BU +#define SITRONIX_P1_YL_REG 0x0CU + +/** + * @} + */ + +/* Exported types ------------------------------------------------------------*/ + +/** @defgroup SITRONIX_Exported_Types SITRONIX Exported Types + * @{ + */ +typedef struct { + uint32_t Radian; + uint32_t OffsetLeftRight; + uint32_t OffsetUpDown; + uint32_t DistanceLeftRight; + uint32_t DistanceUpDown; + uint32_t DistanceZoom; +} SITRONIX_Gesture_Init_t; + +typedef struct { + uint32_t TouchDetected; + uint32_t TouchX; + uint32_t TouchY; +} SITRONIX_State_t; + +typedef struct { + uint32_t TouchDetected; + uint32_t TouchX[SITRONIX_MAX_DETECTABLE_TOUCH]; + uint32_t TouchY[SITRONIX_MAX_DETECTABLE_TOUCH]; + uint32_t TouchWeight[SITRONIX_MAX_DETECTABLE_TOUCH]; + uint32_t TouchEvent[SITRONIX_MAX_DETECTABLE_TOUCH]; + uint32_t TouchArea[SITRONIX_MAX_DETECTABLE_TOUCH]; +} SITRONIX_MultiTouch_State_t; + +typedef struct { + uint8_t IsInitialized; +} SITRONIX_Object_t; + +typedef struct { + uint8_t MultiTouch; + uint8_t Gesture; + uint8_t MaxTouch; + uint32_t MaxXl; + uint32_t MaxYl; +} SITRONIX_Capabilities_t; + +typedef struct { + int32_t (*Init)(SITRONIX_Object_t *); + int32_t (*DeInit)(SITRONIX_Object_t *); + int32_t (*GestureConfig)(SITRONIX_Object_t *, SITRONIX_Gesture_Init_t *); + int32_t (*ReadID)(SITRONIX_Object_t *, uint32_t *); + int32_t (*GetState)(SITRONIX_Object_t *, SITRONIX_State_t *); + int32_t (*GetMultiTouchState)(SITRONIX_Object_t *, + SITRONIX_MultiTouch_State_t *); + int32_t (*GetGesture)(SITRONIX_Object_t *, uint8_t *); + int32_t (*GetCapabilities)(SITRONIX_Object_t *, SITRONIX_Capabilities_t *); + int32_t (*EnableIT)(SITRONIX_Object_t *); + int32_t (*DisableIT)(SITRONIX_Object_t *); + int32_t (*ClearIT)(SITRONIX_Object_t *); + int32_t (*ITStatus)(SITRONIX_Object_t *); +} SITRONIX_TS_Drv_t; + +int32_t SITRONIX_Init(SITRONIX_Object_t *pObj); +int32_t SITRONIX_DeInit(SITRONIX_Object_t *pObj); +int32_t SITRONIX_GestureConfig(SITRONIX_Object_t *pObj, + SITRONIX_Gesture_Init_t *GestureInit); +int32_t SITRONIX_ReadID(SITRONIX_Object_t *pObj, uint32_t *Id); +int32_t SITRONIX_GetState(SITRONIX_Object_t *pObj, SITRONIX_State_t *State); +int32_t SITRONIX_GetMultiTouchState(SITRONIX_Object_t *pObj, + SITRONIX_MultiTouch_State_t *State); +int32_t SITRONIX_GetGesture(SITRONIX_Object_t *pObj, uint8_t *GestureId); +int32_t SITRONIX_EnableIT(SITRONIX_Object_t *pObj); +int32_t SITRONIX_DisableIT(SITRONIX_Object_t *pObj); +int32_t SITRONIX_ITStatus(SITRONIX_Object_t *pObj); +int32_t SITRONIX_ClearIT(SITRONIX_Object_t *pObj); +int32_t SITRONIX_GetCapabilities(SITRONIX_Object_t *pObj, + SITRONIX_Capabilities_t *Capabilities); + +/* Touch screen driver structure initialization */ +SITRONIX_TS_Drv_t SITRONIX_TS_Driver = { + SITRONIX_Init, SITRONIX_DeInit, SITRONIX_GestureConfig, + SITRONIX_ReadID, SITRONIX_GetState, SITRONIX_GetMultiTouchState, + SITRONIX_GetGesture, SITRONIX_GetCapabilities, SITRONIX_EnableIT, + SITRONIX_DisableIT, SITRONIX_ClearIT, SITRONIX_ITStatus}; +/** + * @} + */ + +/** @defgroup SITRONIX_Private_Function_Prototypes SITRONIX Private Function + * Prototypes + * @{ + */ +#if (SITRONIX_AUTO_CALIBRATION_ENABLED == 1) +static int32_t SITRONIX_TS_Calibration(SITRONIX_Object_t *pObj); +static int32_t SITRONIX_Delay(SITRONIX_Object_t *pObj, uint32_t Delay); +#endif /* SITRONIX_AUTO_CALIBRATION_ENABLED == 1 */ +static int32_t SITRONIX_DetectTouch(SITRONIX_Object_t *pObj); +// static int32_t ReadRegWrap(void *handle, uint8_t Reg, uint8_t *Data, +// uint16_t Length); +// static int32_t WriteRegWrap(void *handle, uint8_t Reg, uint8_t *Data, +// uint16_t Length); +// static int32_t ReadDataWrap(void *handle, uint8_t *pData, uint16_t Length); + +/** + * @} + */ + +/** @defgroup SITRONIX_Exported_Functions SITRONIX Exported Functions + * @{ + */ + +/** + * @brief Get SITRONIX sensor capabilities + * @param pObj Component object pointer + * @param Capabilities pointer to SITRONIX sensor capabilities + * @retval Component status + */ +int32_t SITRONIX_GetCapabilities(SITRONIX_Object_t *pObj, + SITRONIX_Capabilities_t *Capabilities) { + /* Prevent unused argument(s) compilation warning */ + (void)(pObj); + + /* Store component's capabilities */ + Capabilities->MultiTouch = 1; + Capabilities->Gesture = + 0; /* Gesture feature is currently not activated on FW chipset */ + Capabilities->MaxTouch = SITRONIX_MAX_DETECTABLE_TOUCH; + Capabilities->MaxXl = SITRONIX_MAX_X_LENGTH; + Capabilities->MaxYl = SITRONIX_MAX_Y_LENGTH; + + return SITRONIX_OK; +} + +/** + * @brief Initialize the SITRONIX communication bus + * from MCU to SITRONIX : ie I2C channel initialization (if required). + * @param pObj Component object pointer + * @retval Component status + */ +int32_t SITRONIX_Init(SITRONIX_Object_t *pObj) { + int32_t ret = SITRONIX_OK; + uint8_t data[28U]; + + if (pObj->IsInitialized == 0U) { + if (sitronix_read_data(data, (uint16_t)sizeof(data)) != SITRONIX_OK) { + ret = SITRONIX_ERROR; + } + + pObj->IsInitialized = 1; + } + + if (ret != SITRONIX_OK) { + ret = SITRONIX_ERROR; + } + + return ret; +} + +/** + * @brief De-Initialize the SITRONIX communication bus + * from MCU to SITRONIX : ie I2C channel initialization (if required). + * @param pObj Component object pointer + * @retval Component status + */ +int32_t SITRONIX_DeInit(SITRONIX_Object_t *pObj) { + if (pObj->IsInitialized == 1U) { + pObj->IsInitialized = 0; + } + + return SITRONIX_OK; +} + +/** + * @brief Configure the SITRONIX gesture + * from MCU to SITRONIX : ie I2C channel initialization (if required). + * @param pObj Component object pointer + * @param GestureInit Gesture init structure + * @retval Component status + */ +int32_t SITRONIX_GestureConfig(SITRONIX_Object_t *pObj, + SITRONIX_Gesture_Init_t *GestureInit) { + return SITRONIX_ERROR; +} + +/** + * @brief Read the SITRONIX device ID, pre initialize I2C in case of need to be + * able to read the SITRONIX device ID, and verify this is a SITRONIX. + * @param pObj Component object pointer + * @param Id Pointer to component's ID + * @retval Component status + */ +int32_t SITRONIX_ReadID(SITRONIX_Object_t *pObj, uint32_t *Id) { + int32_t ret = SITRONIX_OK; + uint8_t data[28]; + uint8_t trial = 0; + + for (trial = 0; trial < 10; trial++) { + if (sitronix_read_data(data, 28) != SITRONIX_OK) { + ret = SITRONIX_ERROR; + } else { + if ((uint32_t)data[0] == SITRONIX_ID) { + *Id = (uint32_t)data[0]; + return ret; + } + } + } + return ret; +} + +uint8_t sitronix_touching = 0; + +/** + * @brief Get the touch screen X and Y positions values + * @param pObj Component object pointer + * @param State Single Touch structure pointer + * @retval Component status. + */ +int32_t SITRONIX_GetState(SITRONIX_Object_t *pObj, SITRONIX_State_t *State) { + int32_t ret = SITRONIX_OK; + uint8_t data[64]; + + State->TouchDetected = (uint32_t)SITRONIX_DetectTouch(pObj); + if (sitronix_read_data(data, (uint16_t)sizeof(data)) != SITRONIX_OK) { + ret = SITRONIX_ERROR; + } else { + if ((uint32_t)data[2] & 0x80) { + sitronix_touching = 1; + } else { + sitronix_touching = 0; + } + + State->TouchX = (((uint32_t)data[2] & SITRONIX_TOUCH_POS_LSB_MASK) << 4); + + /* Send back first ready X position to caller */ + State->TouchX = ((((uint32_t)data[2] & SITRONIX_TOUCH_POS_LSB_MASK) << 4) | + ((uint32_t)data[3])); + /* Send back first ready Y position to caller */ + State->TouchY = (((uint32_t)data[2] & SITRONIX_TOUCH_POS_MSB_MASK) << 8) | + ((uint32_t)data[4]); + } + + return ret; +} + +/** + * @brief Get the touch screen Xn and Yn positions values in multi-touch mode + * @param pObj Component object pointer + * @param State Multi Touch structure pointer + * @retval Component status. + */ +int32_t SITRONIX_GetMultiTouchState(SITRONIX_Object_t *pObj, + SITRONIX_MultiTouch_State_t *State) { + int32_t ret = SITRONIX_OK; + uint8_t data[28]; + + State->TouchDetected = (uint32_t)SITRONIX_DetectTouch(pObj); + + if (sitronix_read_reg(SITRONIX_P1_XH_REG, data, (uint16_t)sizeof(data)) != + SITRONIX_OK) { + ret = SITRONIX_ERROR; + } else { + /* To be implemented */ + } + + return ret; +} + +/** + * @brief Get Gesture ID + * @param pObj Component object pointer + * @param GestureId gesture ID + * @retval Component status + */ +int32_t SITRONIX_GetGesture(SITRONIX_Object_t *pObj, uint8_t *GestureId) { + /* Prevent unused argument(s) compilation warning */ + (void)(pObj); + + /* Always return SITRONIX_OK as feature not supported by SITRONIX */ + return SITRONIX_ERROR; +} + +/** + * @brief Configure the SITRONIX device to generate IT on given INT pin + * connected to MCU as EXTI. + * @param pObj Component object pointer + * @retval Component status + */ +int32_t SITRONIX_EnableIT(SITRONIX_Object_t *pObj) { + /* Prevent unused argument(s) compilation warning */ + (void)(pObj); + + /* Always return SITRONIX_OK as feature not supported by SITRONIX */ + return SITRONIX_ERROR; +} + +/** + * @brief Configure the SITRONIX device to stop generating IT on the given INT + * pin connected to MCU as EXTI. + * @param pObj Component object pointer + * @retval Component status + */ +int32_t SITRONIX_DisableIT(SITRONIX_Object_t *pObj) { + /* Prevent unused argument(s) compilation warning */ + (void)(pObj); + + /* Always return SITRONIX_OK as feature not supported by SITRONIX */ + return SITRONIX_ERROR; +} + +/** + * @brief Get IT status from SITRONIX interrupt status registers + * Should be called Following an EXTI coming to the MCU to know the + * detailed reason of the interrupt. + * @note : This feature is not supported by SITRONIX. + * @param pObj Component object pointer + * @retval Component status + */ +int32_t SITRONIX_ITStatus(SITRONIX_Object_t *pObj) { + /* Prevent unused argument(s) compilation warning */ + (void)(pObj); + + /* Always return SITRONIX_OK as feature not supported by SITRONIX */ + return SITRONIX_ERROR; +} + +/** + * @brief Clear IT status in SITRONIX interrupt status clear registers + * Should be called Following an EXTI coming to the MCU. + * @note : This feature is not supported by SITRONIX. + * @param pObj Component object pointer + * @retval Component status + */ +int32_t SITRONIX_ClearIT(SITRONIX_Object_t *pObj) { + /* Prevent unused argument(s) compilation warning */ + (void)(pObj); + + /* Always return SITRONIX_OK as feature not supported by SITRONIX */ + return SITRONIX_ERROR; +} + +/** + * @} + */ + +/** @defgroup SITRONIX_Private_Functions SITRONIX Private Functions + * @{ + */ + +/** + * @brief Return if there is touches detected or not. + * Try to detect new touches and forget the old ones (reset internal + * global variables). + * @param pObj Component object pointer + * @retval Number of active touches detected (can be between 0 and10) or + * SITRONIX_ERROR in case of error + */ +__attribute__((optimize("-O0"))) int32_t SITRONIX_DetectTouch( + SITRONIX_Object_t *pObj) { + int32_t ret; + uint8_t nb_touch = 0; + static uint8_t first_event = 0; + uint8_t data[28]; + + if (sitronix_read_data((uint8_t *)&data, 28) != SITRONIX_OK) { + ret = SITRONIX_ERROR; + } else { + if (first_event == 0) { + if ((data[0] == 0x09)) { + nb_touch = 1; + first_event = 1; + } else { + nb_touch = 0; + } + } else { + if (data[8] == 0x60) { + nb_touch = 0; + } else { + nb_touch = 1; + } + } + ret = (int32_t)nb_touch; + } + + return ret; +} +// +///** +// * @brief Wrap IO bus read function to component register red function +// * @param handle Component object handle +// * @param Reg The target register address to read +// * @param pData The target register value to be read +// * @param Length buffer size to be read +// * @retval Component status. +// */ +// static int32_t ReadRegWrap(void *handle, uint8_t Reg, uint8_t *pData, +// uint16_t Length) { +// return i2c_mem_read(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, Reg, Length, pData, +// Length, 1000); +//} +// +///** +// * @brief Wrap IO bus write function to component register write function +// * @param handle Component object handle +// * @param Reg The target register address to write +// * @param pData The target register value to be written +// * @param Length buffer size to be written +// * @retval Component status. +// */ +// static int32_t WriteRegWrap(void *handle, uint8_t Reg, uint8_t *pData, +// uint16_t Length) { +// return i2c_mem_write(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, Reg, Length, pData, +// Length, 1000); +//} +// +///** +// * @brief Wrap IO bus read function to component register red function +// * @param handle Component object handle +// * @param pData The target register value to be read +// * @param Length buffer size to be read +// * @retval Component status. +// */ +// static int32_t ReadDataWrap(void *handle, uint8_t *pData, uint16_t Length) { +// return i2c_receive(TOUCH_I2C_INSTANCE, TS_I2C_ADDRESS, pData, Length, 1000); +//} + +/** + ****************************************************************************** + * @file stm32u5x9j_discovery_ts.c + * @author MCD Application Team + * @brief This file provides a set of functions needed to manage the Touch + * Screen on STM32U5x9J-DISCOVERY board. + @verbatim + 1. How To use this driver: + -------------------------- + - This driver is used to drive the touch screen module of the + STM32U5x9J-DISCOVERY board on the LCD mounted on MB1829A daughter board. The + touch screen driver IC is a SITRONIX. + + 2. Driver description: + --------------------- + + Initialization steps: + o Initialize the TS using the BSP_TS_Init() function. You can select + display orientation with "Orientation" parameter of TS_Init_t structure + (portrait, landscape, portrait with 180 degrees rotation or landscape + with 180 degrees rotation). The LCD size properties (width and height) + are also parameters of TS_Init_t and depend on the orientation + selected. + + + Touch screen use + o Call BSP_TS_EnableIT() (BSP_TS_DisableIT()) to enable (disable) touch + screen interrupt. BSP_TS_Callback() is called when TS interrupt occurs. + o Call BSP_TS_GetState() to get the current touch status (detection and + coordinates). + o Call BSP_TS_Set_Orientation() to change the current orientation. + Call BSP_TS_Get_Orientation() to get the current orientation. + o Call BSP_TS_GetCapabilities() to get the SITRONIX capabilities. + o SITRONIX doesn't support multi touch and gesture features. + BSP_TS_Get_MultiTouchState(), BSP_TS_GestureConfig() and + BSP_TS_GetGestureId() functions will return + BSP_ERROR_FEATURE_NOT_SUPPORTED. + + + De-initialization steps: + o De-initialize the touch screen using the BSP_TS_DeInit() function. + + @endverbatim + ****************************************************************************** + * @attention + * + * Copyright (c) 2023 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* TS instances */ +#define TS_INSTANCES_NBR 1U +#define TS_TOUCH_NBR 10U + +/* TS orientations */ +#define TS_ORIENTATION_PORTRAIT 0U +#define TS_ORIENTATION_LANDSCAPE 1U +#define TS_ORIENTATION_PORTRAIT_ROT180 2U +#define TS_ORIENTATION_LANDSCAPE_ROT180 3U + +/** @defgroup STM32U5x9J_DISCOVERY_TS_Exported_Types TS Exported Types + * @{ + */ +typedef struct { + uint32_t Width; /* Screen width */ + uint32_t Height; /* Screen height */ + uint32_t Orientation; /* Touch screen orientation */ + uint32_t Accuracy; /* Expressed in pixel and means the x or y difference vs + old position to consider the new values valid */ +} TS_Init_t; + +typedef struct { + uint8_t MultiTouch; + uint8_t Gesture; + uint8_t MaxTouch; + uint32_t MaxXl; + uint32_t MaxYl; +} TS_Capabilities_t; + +typedef struct { + uint32_t TouchDetected; + uint32_t TouchX; + uint32_t TouchY; +} TS_State_t; + +typedef struct { + uint32_t TouchDetected; + uint32_t TouchX[2]; + uint32_t TouchY[2]; + uint32_t TouchWeight[2]; + uint32_t TouchEvent[2]; + uint32_t TouchArea[2]; +} TS_MultiTouch_State_t; + +typedef struct { + uint32_t Radian; + uint32_t OffsetLeftRight; + uint32_t OffsetUpDown; + uint32_t DistanceLeftRight; + uint32_t DistanceUpDown; + uint32_t DistanceZoom; +} TS_Gesture_Config_t; + +typedef struct { + uint32_t Width; + uint32_t Height; + uint32_t Orientation; + uint32_t Accuracy; + uint32_t MaxX; + uint32_t MaxY; + uint32_t PreviousX[TS_TOUCH_NBR]; + uint32_t PreviousY[TS_TOUCH_NBR]; +} TS_Ctx_t; + +typedef struct { + int32_t (*Init)(void *); + int32_t (*DeInit)(void *); + int32_t (*GestureConfig)(void *, void *); + int32_t (*ReadID)(void *, uint32_t *); + int32_t (*GetState)(void *, void *); + int32_t (*GetMultiTouchState)(void *, void *); + int32_t (*GetGesture)(void *, void *); + int32_t (*GetCapabilities)(void *, void *); + int32_t (*EnableIT)(void *); + int32_t (*DisableIT)(void *); + int32_t (*ClearIT)(void *); + int32_t (*ITStatus)(void *); +} TS_Drv_t; + +/* DSI TS INT pin */ +#define TS_INT_PIN GPIO_PIN_8 +#define TS_INT_GPIO_PORT GPIOE +#define TS_INT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE() +#define TS_INT_GPIO_CLK_DISABLE() __HAL_RCC_GPIOE_CLK_DISABLE() +#define TS_INT_EXTI_IRQn EXTI8_IRQn + +/* Includes ------------------------------------------------------------------*/ +//#include "stm32u5x9j_discovery_ts.h" +//#include "stm32u5x9j_discovery.h" + +/** @addtogroup BSP + * @{ + */ + +/** @addtogroup STM32U5x9J_DISCOVERY + * @{ + */ + +/** @defgroup STM32U5x9J_DISCOVERY_TS TS + * @{ + */ + +/** @defgroup STM32U5x9J_DISCOVERY_TS_Private_Defines TS Private Defines + * @{ + */ +/** + * @} + */ + +/** @defgroup STM32U5x9J_DISCOVERY_TS_Private_TypesDefinitions TS Private + * TypesDefinitions + * @{ + */ +typedef void (*BSP_EXTI_LineCallback)(void); +/** + * @} + */ + +/** @addtogroup STM32U5x9J_DISCOVERY_TS_Exported_Variables TS Exported Variables + * @{ + */ +void *Ts_CompObj[TS_INSTANCES_NBR] = {0}; +TS_Drv_t *Ts_Drv[TS_INSTANCES_NBR] = {0}; +TS_Ctx_t Ts_Ctx[TS_INSTANCES_NBR] = {0}; +EXTI_HandleTypeDef hts_exti[TS_INSTANCES_NBR]; +IRQn_Type Ts_IRQn[TS_INSTANCES_NBR] = {EXTI15_IRQn}; + +/** + * @} + */ + +/** @defgroup STM32U5x9J_DISCOVERY_TS_Private_FunctionPrototypes TS Private + * Function Prototypes + * @{ + */ +static int32_t SITRONIX_Probe(uint32_t Instance); + +/** + * @} + */ + +/** @addtogroup STM32U5x9J_DISCOVERY_TS_Exported_Functions + * @{ + */ +/** + * @brief Initialize the TS. + * @param Instance TS Instance. + * @param TS_Init Pointer to TS initialization structure. + * @retval BSP status. + */ +int32_t BSP_TS_Init(uint32_t Instance, TS_Init_t *TS_Init) { + int32_t status = BSP_ERROR_NONE; + + if ((TS_Init == NULL) || (Instance >= TS_INSTANCES_NBR)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Probe the TS driver */ + if (SITRONIX_Probe(Instance) != BSP_ERROR_NONE) { + status = BSP_ERROR_COMPONENT_FAILURE; + } else { + TS_Capabilities_t Capabilities; + uint32_t i; + /* Store parameters on TS context */ + Ts_Ctx[Instance].Width = TS_Init->Width; + Ts_Ctx[Instance].Height = TS_Init->Height; + Ts_Ctx[Instance].Orientation = TS_Init->Orientation; + Ts_Ctx[Instance].Accuracy = TS_Init->Accuracy; + /* Get capabilities to retrieve maximum values of X and Y */ + if (Ts_Drv[Instance]->GetCapabilities(Ts_CompObj[Instance], + &Capabilities) < 0) { + status = BSP_ERROR_COMPONENT_FAILURE; + } else { + /* Store maximum X and Y on context */ + Ts_Ctx[Instance].MaxX = Capabilities.MaxXl; + Ts_Ctx[Instance].MaxY = Capabilities.MaxYl; + /* Initialize previous position in order to always detect first touch */ + for (i = 0; i < TS_TOUCH_NBR; i++) { + Ts_Ctx[Instance].PreviousX[i] = + TS_Init->Width + TS_Init->Accuracy + 1U; + Ts_Ctx[Instance].PreviousY[i] = + TS_Init->Height + TS_Init->Accuracy + 1U; + } + } + } + } + + return status; +} + +/** + * @brief De-Initialize the TS. + * @param Instance TS Instance. + * @retval BSP status. + */ +int32_t BSP_TS_DeInit(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + + if (Instance >= TS_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* De-Init the TS driver */ + if (Ts_Drv[Instance]->DeInit(Ts_CompObj[Instance]) < 0) { + status = BSP_ERROR_COMPONENT_FAILURE; + } + } + + return status; +} + +/** + * @brief Enable the TS interrupt. + * @param Instance TS Instance. + * @retval BSP status. + */ +int32_t BSP_TS_EnableIT(uint32_t Instance) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(Instance); + + GPIO_InitTypeDef gpio_init_structure; + + __HAL_RCC_GPIOE_CLK_ENABLE(); + + /* Configure Interrupt mode for TS detection pin */ + gpio_init_structure.Pin = TS_INT_PIN; + gpio_init_structure.Pull = GPIO_PULLUP; + gpio_init_structure.Speed = GPIO_SPEED_FREQ_HIGH; + gpio_init_structure.Mode = GPIO_MODE_IT_FALLING; + HAL_GPIO_Init(TS_INT_GPIO_PORT, &gpio_init_structure); + + /* Enable and set Touch screen EXTI Interrupt to the lowest priority */ + HAL_NVIC_SetPriority((IRQn_Type)(TS_INT_EXTI_IRQn), 0x0F, 0x00); + HAL_NVIC_EnableIRQ((IRQn_Type)(TS_INT_EXTI_IRQn)); + + return BSP_ERROR_NONE; +} + +/** + * @brief Disable the TS interrupt. + * @param Instance TS Instance. + * @retval BSP status. + */ +int32_t BSP_TS_DisableIT(uint32_t Instance) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(Instance); + + /* To be Implemented */ + return BSP_ERROR_NONE; +} + +/** + * @brief Set the TS orientation. + * @param Instance TS Instance. + * @param Orientation TS orientation. + * @retval BSP status. + */ +int32_t BSP_TS_Set_Orientation(uint32_t Instance, uint32_t Orientation) { + int32_t status = BSP_ERROR_NONE; + uint32_t temp; + uint32_t i; + + if ((Instance >= TS_INSTANCES_NBR) || + (Orientation > TS_ORIENTATION_LANDSCAPE_ROT180)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Update TS context if orientation is changed from/to portrait to/from + * landscape */ + if ((((Ts_Ctx[Instance].Orientation == TS_ORIENTATION_LANDSCAPE) || + (Ts_Ctx[Instance].Orientation == TS_ORIENTATION_LANDSCAPE_ROT180)) && + ((Orientation == TS_ORIENTATION_PORTRAIT) || + (Orientation == TS_ORIENTATION_PORTRAIT_ROT180))) || + (((Ts_Ctx[Instance].Orientation == TS_ORIENTATION_PORTRAIT) || + (Ts_Ctx[Instance].Orientation == TS_ORIENTATION_PORTRAIT_ROT180)) && + ((Orientation == TS_ORIENTATION_LANDSCAPE) || + (Orientation == TS_ORIENTATION_LANDSCAPE_ROT180)))) { + /* Invert width and height */ + temp = Ts_Ctx[Instance].Width; + Ts_Ctx[Instance].Width = Ts_Ctx[Instance].Height; + Ts_Ctx[Instance].Height = temp; + /* Invert MaxX and MaxY */ + temp = Ts_Ctx[Instance].MaxX; + Ts_Ctx[Instance].MaxX = Ts_Ctx[Instance].MaxY; + Ts_Ctx[Instance].MaxY = temp; + } + /* Store orientation on TS context */ + Ts_Ctx[Instance].Orientation = Orientation; + /* Reset previous position */ + for (i = 0; i < TS_TOUCH_NBR; i++) { + Ts_Ctx[Instance].PreviousX[i] = + Ts_Ctx[Instance].Width + Ts_Ctx[Instance].Accuracy + 1U; + Ts_Ctx[Instance].PreviousY[i] = + Ts_Ctx[Instance].Height + Ts_Ctx[Instance].Accuracy + 1U; + } + } + + return status; +} + +/** + * @brief Get the TS orientation. + * @param Instance TS Instance. + * @param Orientation Pointer to TS orientation. + * @retval BSP status. + */ +int32_t BSP_TS_Get_Orientation(uint32_t Instance, uint32_t *Orientation) { + int32_t status = BSP_ERROR_NONE; + + if ((Instance >= TS_INSTANCES_NBR) || (Orientation == NULL)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Get orientation from TS context */ + *Orientation = Ts_Ctx[Instance].Orientation; + } + + return status; +} + +/** + * @brief Get position of a single touch. + * @param Instance TS Instance. + * @param TS_State Pointer to single touch structure. + * @retval BSP status. + */ +int32_t BSP_TS_GetState(uint32_t Instance, TS_State_t *TS_State) { + int32_t status = BSP_ERROR_NONE; + uint32_t x_oriented; + uint32_t y_oriented; + uint32_t x_diff; + uint32_t y_diff; + + if (Instance >= TS_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + SITRONIX_State_t state; + + /* Get each touch coordinates */ + if (Ts_Drv[Instance]->GetState(Ts_CompObj[Instance], &state) < 0) { + status = BSP_ERROR_COMPONENT_FAILURE; + } /* Check and update the number of touches active detected */ + else if (state.TouchDetected != 0U) { + x_oriented = /*Ts_Ctx[Instance].MaxX -*/ state.TouchX; + y_oriented = /*Ts_Ctx[Instance].MaxY -*/ state.TouchY; + + /* Apply boundary */ + TS_State->TouchX = + (x_oriented * Ts_Ctx[Instance].Width) / (Ts_Ctx[Instance].MaxX); + TS_State->TouchY = + (y_oriented * Ts_Ctx[Instance].Height) / (Ts_Ctx[Instance].MaxY); + /* Store Current TS state */ + TS_State->TouchDetected = state.TouchDetected; + + /* Check accuracy */ + x_diff = (TS_State->TouchX > Ts_Ctx[Instance].PreviousX[0]) + ? (TS_State->TouchX - Ts_Ctx[Instance].PreviousX[0]) + : (Ts_Ctx[Instance].PreviousX[0] - TS_State->TouchX); + + y_diff = (TS_State->TouchY > Ts_Ctx[Instance].PreviousY[0]) + ? (TS_State->TouchY - Ts_Ctx[Instance].PreviousY[0]) + : (Ts_Ctx[Instance].PreviousY[0] - TS_State->TouchY); + + if ((x_diff > Ts_Ctx[Instance].Accuracy) || + (y_diff > Ts_Ctx[Instance].Accuracy)) { + /* New touch detected */ + Ts_Ctx[Instance].PreviousX[0] = TS_State->TouchX; + Ts_Ctx[Instance].PreviousY[0] = TS_State->TouchY; + } else { + TS_State->TouchX = Ts_Ctx[Instance].PreviousX[0]; + TS_State->TouchY = Ts_Ctx[Instance].PreviousY[0]; + } + } else { + TS_State->TouchDetected = 0U; + TS_State->TouchX = Ts_Ctx[Instance].PreviousX[0]; + TS_State->TouchY = Ts_Ctx[Instance].PreviousY[0]; + } + } + + return status; +} + +/** + * @brief Get positions of multiple touch. + * @param Instance TS Instance. + * @param TS_State Pointer to multiple touch structure. + * @retval BSP status. + */ +int32_t BSP_TS_Get_MultiTouchState(const uint32_t Instance, + TS_MultiTouch_State_t *TS_State) { + int32_t status; + + UNUSED(TS_State); + + if (Instance >= TS_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Feature not supported in this release */ + status = BSP_ERROR_FEATURE_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief Configure gesture on TS. + * @param Instance TS Instance. + * @param GestureConfig Pointer to gesture configuration structure. + * @retval BSP status. + */ +int32_t BSP_TS_GestureConfig(const uint32_t Instance, + TS_Gesture_Config_t *GestureConfig) { + int32_t status; + + if ((Instance >= TS_INSTANCES_NBR) || (GestureConfig == NULL)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Feature not supported */ + status = BSP_ERROR_FEATURE_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief Get gesture. + * @param Instance TS Instance. + * @param GestureId Pointer to gesture. + * @retval BSP status. + */ +int32_t BSP_TS_GetGestureId(const uint32_t Instance, uint32_t *GestureId) { + int32_t status; + + if ((Instance >= TS_INSTANCES_NBR) || (GestureId == NULL)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Feature not supported */ + status = BSP_ERROR_FEATURE_NOT_SUPPORTED; + } + + return status; +} + +/** + * @brief Get the TS capabilities. + * @param Instance TS Instance. + * @param Capabilities Pointer to TS capabilities structure. + * @retval BSP status. + */ +int32_t BSP_TS_GetCapabilities(uint32_t Instance, + TS_Capabilities_t *Capabilities) { + int32_t status = BSP_ERROR_NONE; + + if ((Instance >= TS_INSTANCES_NBR) || (Capabilities == NULL)) { + status = BSP_ERROR_WRONG_PARAM; + } else { + /* Get the TS driver capabilities */ + if (Ts_Drv[Instance]->GetCapabilities(Ts_CompObj[Instance], Capabilities) < + 0) { + status = BSP_ERROR_COMPONENT_FAILURE; + } else { + /* Update maximum X and Y according orientation */ + if ((Ts_Ctx[Instance].Orientation == TS_ORIENTATION_LANDSCAPE) || + (Ts_Ctx[Instance].Orientation == TS_ORIENTATION_LANDSCAPE_ROT180)) { + uint32_t tmp; + tmp = Capabilities->MaxXl; + Capabilities->MaxXl = Capabilities->MaxYl; + Capabilities->MaxYl = tmp; + } + } + } + + return status; +} + +/** + * @brief TS Callback. + * @param Instance TS Instance. + * @retval None. + */ +__weak void BSP_TS_Callback(uint32_t Instance) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(Instance); + + /* This function should be implemented by the user application. + It is called into this driver when an event on TS touch detection */ +} + +/** + * @brief BSP TS interrupt handler. + * @param Instance TS Instance. + * @retval None. + */ +void BSP_TS_IRQHandler(uint32_t Instance) { + /* Prevent unused argument(s) compilation warning */ + UNUSED(Instance); + + /* To be implemented */ +} +/** + * @} + */ + +/** @defgroup STM32U5x9J_DISCOVERY_TS_Private_Functions TS Private Functions + * @{ + */ +/** + * @brief Probe the SITRONIX TS driver. + * @param Instance TS Instance. + * @retval BSP status. + */ +static int32_t SITRONIX_Probe(uint32_t Instance) { + int32_t status; + static SITRONIX_Object_t SITRONIXObj; + + Ts_CompObj[Instance] = &SITRONIXObj; + Ts_Drv[Instance] = (TS_Drv_t *)&SITRONIX_TS_Driver; + if (Ts_Drv[Instance]->Init(Ts_CompObj[Instance]) < 0) { + status = BSP_ERROR_COMPONENT_FAILURE; + } else { + status = BSP_ERROR_NONE; + } + + return status; +} + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ + +#include +#include "touch.h" + +void touch_init(void) { + TS_Init_t TsInit; + + /* Initialize the TouchScreen */ + TsInit.Width = 480; + TsInit.Height = 480; + TsInit.Orientation = 0; + TsInit.Accuracy = 10; + + BSP_TS_Init(0, &TsInit); +} +void touch_power_on(void) {} +void touch_power_off(void) {} +void touch_sensitivity(uint8_t value) {} + +uint32_t touch_is_detected(void) { return sitronix_touching != 0; } + +uint32_t touch_read(void) { + TS_State_t state = {0}; + static uint32_t xy = 0; + static TS_State_t state_last = {0}; + // static uint16_t first = 1; + static uint16_t touching = 0; + + BSP_TS_GetState(0, &state); + + state.TouchDetected = touch_is_detected(); + state.TouchY = state.TouchY > 120 ? state.TouchY - 120 : 0; + state.TouchX = state.TouchX > 120 ? state.TouchX - 120 : 0; + + if (!touch_is_detected()) { + // if (state.TouchDetected == 0) { + if (touching) { + // touch end + memcpy(&state_last, &state, sizeof(state)); + touching = 0; + return TOUCH_END | xy; + } + return 0; + } + + if (state.TouchDetected == 0) { + return 0; + } + + // if (first != 0) { + // memcpy(&state_last, &state, sizeof(state)); + // first = 0; + // return 0; + // } + + if ((state.TouchDetected == 0 && state_last.TouchDetected == 0) || + memcmp(&state, &state_last, sizeof(state)) == 0) { + // no change detected + return 0; + } + + xy = touch_pack_xy(state.TouchX, state.TouchY); + + if (state.TouchDetected && !state_last.TouchDetected) { + // touch start + memcpy(&state_last, &state, sizeof(state)); + touching = 1; + return TOUCH_START | xy; + } else if (!state.TouchDetected && state_last.TouchDetected) { + // touch end + memcpy(&state_last, &state, sizeof(state)); + touching = 0; + return TOUCH_END | xy; + } else { + // touch move + memcpy(&state_last, &state, sizeof(state)); + return TOUCH_MOVE | xy; + } + + return 0; +} + +void touch_wait_until_ready(void) {} diff --git a/core/embed/trezorhal/stm32u5/touch/sitronix.h b/core/embed/trezorhal/stm32u5/touch/sitronix.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/core/embed/trezorhal/stm32u5/trustzone.c b/core/embed/trezorhal/stm32u5/trustzone.c new file mode 100644 index 00000000000..e760217cc20 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/trustzone.c @@ -0,0 +1,149 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include + +#include STM32_HAL_H + +#ifdef BOARDLOADER + +#define SAU_INIT_CTRL_ENABLE 1 +#define SAU_INIT_CTRL_ALLNS 0 +#define SAU_INIT_REGION(n, start, end, sec) \ + SAU->RNR = ((n)&SAU_RNR_REGION_Msk); \ + SAU->RBAR = ((start)&SAU_RBAR_BADDR_Msk); \ + SAU->RLAR = ((end)&SAU_RLAR_LADDR_Msk) | \ + (((sec) << SAU_RLAR_NSC_Pos) & SAU_RLAR_NSC_Msk) | 1U + +static void trustzone_configure_sau(void) { + SAU_INIT_REGION(0, 0x0BF90000, 0x0BFA8FFF, 0); // OTP etc + + SAU->CTRL = + ((SAU_INIT_CTRL_ENABLE << SAU_CTRL_ENABLE_Pos) & SAU_CTRL_ENABLE_Msk) | + ((SAU_INIT_CTRL_ALLNS << SAU_CTRL_ALLNS_Pos) & SAU_CTRL_ALLNS_Msk); +} + +// Configure ARMCortex-M33 SCB and FPU security +static void trustzone_configure_arm(void) { + // Enable FPU in both secure and non-secure modes + SCB->NSACR |= SCB_NSACR_CP10_Msk | SCB_NSACR_CP11_Msk; + + // Treat FPU registers as non-secure + FPU->FPCCR &= ~FPU_FPCCR_TS_Msk; + // CLRONRET field is accessible from both security states + FPU->FPCCR &= ~FPU_FPCCR_CLRONRETS_Msk; + // FPU registers are cleared on exception return + FPU->FPCCR |= FPU_FPCCR_CLRONRET_Msk; +} + +// Configure SRAM security +static void trustzone_configure_sram(void) { + MPCBB_ConfigTypeDef mpcbb = {0}; + + // No exceptions on illegal access + mpcbb.SecureRWIllegalMode = GTZC_MPCBB_SRWILADIS_DISABLE; + // Settings of SRAM clock in RCC is secure + mpcbb.InvertSecureState = GTZC_MPCBB_INVSECSTATE_NOT_INVERTED; + // Set configuration as unlocked + mpcbb.AttributeConfig.MPCBB_LockConfig_array[0] = 0x00000000U; + + // Set all blocks secured & unprivileged + for (int index = 0; index < GTZC_MPCBB_NB_VCTR_REG_MAX; index++) { + mpcbb.AttributeConfig.MPCBB_SecConfig_array[index] = 0xFFFFFFFFU; + mpcbb.AttributeConfig.MPCBB_PrivConfig_array[index] = 0x00000000U; + } + + HAL_GTZC_MPCBB_ConfigMem(SRAM1_BASE, &mpcbb); + HAL_GTZC_MPCBB_ConfigMem(SRAM2_BASE, &mpcbb); + HAL_GTZC_MPCBB_ConfigMem(SRAM3_BASE, &mpcbb); + HAL_GTZC_MPCBB_ConfigMem(SRAM4_BASE, &mpcbb); +#if defined STM32U5A9xx | defined STM32U5G9xx + HAL_GTZC_MPCBB_ConfigMem(SRAM5_BASE, &mpcbb); +#endif +#if defined STM32U5G9xx + HAL_GTZC_MPCBB_ConfigMem(SRAM6_BASE, &mpcbb); +#endif +} + +static void trustzone_configure_fsmc(void) { + __HAL_RCC_FMC_CLK_ENABLE(); + MPCWM_ConfigTypeDef mpcwm = {0}; + + mpcwm.AreaId = GTZC_TZSC_MPCWM_ID1; + mpcwm.AreaStatus = ENABLE; + mpcwm.Attribute = GTZC_TZSC_MPCWM_REGION_SEC; + mpcwm.Length = 128 * 1024; + mpcwm.Offset = 0; + mpcwm.Lock = GTZC_TZSC_MPCWM_LOCK_OFF; + HAL_GTZC_TZSC_MPCWM_ConfigMemAttributes(FMC_BANK1, &mpcwm); +} + +// Configure FLASH security +static void trustzone_configure_flash(void) { + FLASH_BBAttributesTypeDef flash_bb = {0}; + + // Set all blocks as secured + for (int index = 0; index < FLASH_BLOCKBASED_NB_REG; index++) { + flash_bb.BBAttributes_array[index] = 0xFFFFFFFF; + } + + flash_bb.Bank = FLASH_BANK_1; + flash_bb.BBAttributesType = FLASH_BB_SEC; + HAL_FLASHEx_ConfigBBAttributes(&flash_bb); + + flash_bb.Bank = FLASH_BANK_2; + flash_bb.BBAttributesType = FLASH_BB_SEC; + HAL_FLASHEx_ConfigBBAttributes(&flash_bb); +} + +void trustzone_init_boardloader(void) { + // Configure ARM SCB/FBU security + trustzone_configure_arm(); + + // Configure SAU security attributes + trustzone_configure_sau(); + + // Enable GTZC (Global Trust-Zone Controller) peripheral clock + __HAL_RCC_GTZC1_CLK_ENABLE(); + __HAL_RCC_GTZC2_CLK_ENABLE(); + + // Configure SRAM security attributes + trustzone_configure_sram(); + + // Configure FLASH security attributes + trustzone_configure_flash(); + + // Configure FSMC security attributes + trustzone_configure_fsmc(); + + // Make all peripherals secure + HAL_GTZC_TZSC_ConfigPeriphAttributes(GTZC_PERIPH_ALL, GTZC_TZSC_PERIPH_SEC); + + // Clear all illegal access flags in GTZC TZIC + HAL_GTZC_TZIC_ClearFlag(GTZC_PERIPH_ALL); + + // Enable all illegal access interrupts in GTZC TZIC + HAL_GTZC_TZIC_EnableIT(GTZC_PERIPH_ALL); + + // Enable GTZC secure interrupt + HAL_NVIC_SetPriority(GTZC_IRQn, 0, 0); // Highest priority level + HAL_NVIC_EnableIRQ(GTZC_IRQn); +} + +#endif // BOARDLOADER diff --git a/core/embed/trezorhal/stm32u5/usb.c b/core/embed/trezorhal/stm32u5/usb.c new file mode 120000 index 00000000000..e05e3c0912d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb.c @@ -0,0 +1 @@ +../stm32f4/usb.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usb_hid-impl.h b/core/embed/trezorhal/stm32u5/usb_hid-impl.h new file mode 120000 index 00000000000..89e47b5ef08 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb_hid-impl.h @@ -0,0 +1 @@ +../stm32f4/usb_hid-impl.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usb_vcp-impl.h b/core/embed/trezorhal/stm32u5/usb_vcp-impl.h new file mode 120000 index 00000000000..be4e3b8e740 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb_vcp-impl.h @@ -0,0 +1 @@ +../stm32f4/usb_vcp-impl.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usb_webusb-impl.h b/core/embed/trezorhal/stm32u5/usb_webusb-impl.h new file mode 120000 index 00000000000..749c2f52f94 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usb_webusb-impl.h @@ -0,0 +1 @@ +../stm32f4/usb_webusb-impl.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_conf.c b/core/embed/trezorhal/stm32u5/usbd_conf.c new file mode 120000 index 00000000000..96c576f9821 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_conf.c @@ -0,0 +1 @@ +../stm32f4/usbd_conf.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_conf.h b/core/embed/trezorhal/stm32u5/usbd_conf.h new file mode 120000 index 00000000000..21f3e5266eb --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_conf.h @@ -0,0 +1 @@ +../stm32f4/usbd_conf.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_core.c b/core/embed/trezorhal/stm32u5/usbd_core.c new file mode 120000 index 00000000000..554c29cbfa9 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_core.c @@ -0,0 +1 @@ +../stm32f4/usbd_core.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_core.h b/core/embed/trezorhal/stm32u5/usbd_core.h new file mode 120000 index 00000000000..ee7585f5a30 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_core.h @@ -0,0 +1 @@ +../stm32f4/usbd_core.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ctlreq.c b/core/embed/trezorhal/stm32u5/usbd_ctlreq.c new file mode 120000 index 00000000000..a9065b0abe5 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ctlreq.c @@ -0,0 +1 @@ +../stm32f4/usbd_ctlreq.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ctlreq.h b/core/embed/trezorhal/stm32u5/usbd_ctlreq.h new file mode 120000 index 00000000000..8f764f56a91 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ctlreq.h @@ -0,0 +1 @@ +../stm32f4/usbd_ctlreq.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_def.h b/core/embed/trezorhal/stm32u5/usbd_def.h new file mode 120000 index 00000000000..72e5b4b70f2 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_def.h @@ -0,0 +1 @@ +../stm32f4/usbd_def.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ioreq.c b/core/embed/trezorhal/stm32u5/usbd_ioreq.c new file mode 120000 index 00000000000..cf5c0a30e28 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ioreq.c @@ -0,0 +1 @@ +../stm32f4/usbd_ioreq.c \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/usbd_ioreq.h b/core/embed/trezorhal/stm32u5/usbd_ioreq.h new file mode 120000 index 00000000000..06da29b5c6d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/usbd_ioreq.h @@ -0,0 +1 @@ +../stm32f4/usbd_ioreq.h \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/util.s b/core/embed/trezorhal/stm32u5/util.s new file mode 100644 index 00000000000..be2eff48bf5 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/util.s @@ -0,0 +1,205 @@ + .syntax unified + + .text + + .global memset_reg + .type memset_reg, STT_FUNC +memset_reg: + // call with the following (note that the arguments are not validated prior to use): + // r0 - address of first word to write (inclusive) + // r1 - address of first word following the address in r0 to NOT write (exclusive) + // r2 - word value to be written + // both addresses in r0 and r1 needs to be divisible by 4! + cmp r0, r1 + beq .L_loop_end + .L_loop_begin: + str r2, [r0], 4 // store the word in r2 to the address in r0, post-indexed + cmp r0, r1 + bne .L_loop_begin + .L_loop_end: + bx lr + + // Jump to address given in first argument R0 that points to next's stage's VTOR + // Clear memory and all registers before jump + .global jump_to + .type jump_to, STT_FUNC +jump_to: + mov r4, r0 // save input argument r0 (the address of the next stage's vector table) (r4 is callee save) + // this subroutine re-points the exception handlers before the C code + // that comprises them has been given a good environment to run. + // therefore, this code needs to disable interrupts before the VTOR + // update. then, the reset_handler of the next stage needs to re-enable interrupts. + // the following prevents activation of all exceptions except Non-Maskable Interrupt (NMI). + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.8: + // "there is no requirement to insert memory barrier instructions after CPSID". + cpsid f + // wipe memory at the end of the current stage of code + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + mov lr, r4 + // clear out the general purpose registers before the next stage's except the register with flag R11 + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + // give the next stage a fresh main stack pointer + ldr r0, [lr] // set r0 to the main stack pointer in the next stage's vector table + msr msp, r0 // give the next stage its main stack pointer + // point to the next stage's exception handlers + // AN321, section 4.11: "a memory barrier is not required after a VTOR update" + .set SCB_VTOR, 0xE000ED08 // reference "Cortex-M4 Devices Generic User Guide" section 4.3 + ldr r0, =SCB_VTOR + str lr, [r0] + mov r0, r1 // zero out r0 + // go on to the next stage + ldr lr, [lr, 4] // set lr to the next stage's reset_handler + bx lr + + .global jump_to_unprivileged + .type jump_to_unprivileged, STT_FUNC +jump_to_unprivileged: + mov r4, r0 // save input argument r0 (the address of the next stage's vector table) (r4 is callee save) + // this subroutine re-points the exception handlers before the C code + // that comprises them has been given a good environment to run. + // therefore, this code needs to disable interrupts before the VTOR + // update. then, the reset_handler of the next stage needs to re-enable interrupts. + // the following prevents activation of all exceptions except Non-Maskable Interrupt (NMI). + // according to "ARM Cortex-M Programming Guide to Memory Barrier Instructions" Application Note 321, section 4.8: + // "there is no requirement to insert memory barrier instructions after CPSID". + cpsid f + // wipe memory at the end of the current stage of code + ldr r2, =0 // r2 - the word-sized value to be written + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + mov lr, r4 + // clear out the general purpose registers before the next stage's code can run (even the NMI exception handler) + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + // give the next stage a fresh main stack pointer + ldr r0, [lr] // set r0 to the main stack pointer in the next stage's vector table + msr msp, r0 // give the next stage its main stack pointer + // point to the next stage's exception handlers + // AN321, section 4.11: "a memory barrier is not required after a VTOR update" + .set SCB_VTOR, 0xE000ED08 // reference "Cortex-M4 Devices Generic User Guide" section 4.3 + ldr r0, =SCB_VTOR + str lr, [r0] + mov r0, r1 // zero out r0 + // go on to the next stage + ldr lr, [lr, 4] // set lr to the next stage's reset_handler + // switch to unprivileged mode + ldr r0, =1 + msr control, r0 + isb + // jump + bx lr + + .global shutdown_privileged + .type shutdown_privileged, STT_FUNC + // The function must be called from the privileged mode +shutdown_privileged: + cpsid f // disable all exceptions (except for NMI), the instruction is ignored in unprivileged mode + // if the exceptions weren't disabled, an exception handler (for example systick handler) + // could be called after the memory is erased, which would lead to another exception + ldr r0, =0 + mov r1, r0 + mov r2, r0 + mov r3, r0 + mov r4, r0 + mov r5, r0 + mov r6, r0 + mov r7, r0 + mov r8, r0 + mov r9, r0 + mov r10, r0 + mov r11, r0 + mov r12, r0 + ldr lr, =0xffffffff + + ldr r0, =sram1_start // r0 - point to beginning of SRAM + ldr r1, =sram1_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram2_start // r0 - point to beginning of SRAM + ldr r1, =sram2_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram4_start // r0 - point to beginning of SRAM + ldr r1, =sram4_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =sram6_start // r0 - point to beginning of SRAM + ldr r1, =sram6_end // r1 - point to byte after the end of SRAM + bl memset_reg + ldr r0, =boot_args_start // r0 - point to beginning of boot args + ldr r1, =boot_args_end // r1 - point to byte after the end of boot args + bl memset_reg + ldr r0, =sram3_start // r0 - point to beginning of SRAM + ldr r1, =__fb_start // r1 - point to beginning of framebuffer + bl memset_reg + ldr r0, =__fb_end // r0 - point to end of framebuffer + ldr r1, =sram5_end // r1 - point to byte after the end of SRAM + bl memset_reg + + ldr r0, =1 + msr control, r0 // jump to unprivileged mode + ldr r0, =0 + b . // loop forever + + .end diff --git a/core/embed/trezorhal/stm32u5/vectortable.s b/core/embed/trezorhal/stm32u5/vectortable.s new file mode 100644 index 00000000000..2a9e9cb6530 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/vectortable.s @@ -0,0 +1,177 @@ + .syntax unified + + .text + + .global default_handler + .type default_handler, STT_FUNC +default_handler: + b shutdown_privileged + + .macro add_handler symbol_name:req + .word \symbol_name + .weak \symbol_name + .thumb_set \symbol_name, default_handler + .endm + + // Reference: + // Table 62 - STM32F427 Reference manual (RM0090) + // Section B1.5 - ARMv7-M Architecture Reference Manual + .section .vector_table, "a" +vector_table: + .word main_stack_base // defined in linker script + add_handler reset_handler + add_handler NMI_Handler + add_handler HardFault_Handler + add_handler MemManage_Handler + add_handler BusFault_Handler + add_handler UsageFault_Handler + add_handler SecureFault_Handler + add_handler architecture_reserved_handler + add_handler architecture_reserved_handler + add_handler architecture_reserved_handler + add_handler SVC_Handler + add_handler DebugMon_Handler + add_handler architecture_reserved_handler + add_handler PendSV_Handler + add_handler SysTick_Handler + add_handler WWDG_IRQHandler + add_handler PVD_PVM_IRQHandler + add_handler RTC_IRQHandler + add_handler RTC_S_IRQHandler + add_handler TAMP_IRQHandler + add_handler RAMCFG_IRQHandler + add_handler FLASH_IRQHandler + add_handler FLASH_S_IRQHandler + add_handler GTZC_IRQHandler + add_handler RCC_IRQHandler + add_handler RCC_S_IRQHandler + add_handler EXTI0_IRQHandler + add_handler EXTI1_IRQHandler + add_handler EXTI2_IRQHandler + add_handler EXTI3_IRQHandler + add_handler EXTI4_IRQHandler + add_handler EXTI5_IRQHandler + add_handler EXTI6_IRQHandler + add_handler EXTI7_IRQHandler + add_handler EXTI8_IRQHandler + add_handler EXTI9_IRQHandler + add_handler EXTI10_IRQHandler + add_handler EXTI11_IRQHandler + add_handler EXTI12_IRQHandler + add_handler EXTI13_IRQHandler + add_handler EXTI14_IRQHandler + add_handler EXTI15_IRQHandler + add_handler IWDG_IRQHandler + add_handler SAES_IRQHandler + add_handler GPDMA1_Channel0_IRQHandler + add_handler GPDMA1_Channel1_IRQHandler + add_handler GPDMA1_Channel2_IRQHandler + add_handler GPDMA1_Channel3_IRQHandler + add_handler GPDMA1_Channel4_IRQHandler + add_handler GPDMA1_Channel5_IRQHandler + add_handler GPDMA1_Channel6_IRQHandler + add_handler GPDMA1_Channel7_IRQHandler + add_handler ADC1_2_IRQHandler + add_handler DAC1_IRQHandler + add_handler FDCAN1_IT0_IRQHandler + add_handler FDCAN1_IT1_IRQHandler + add_handler TIM1_BRK_IRQHandler + add_handler TIM1_UP_IRQHandler + add_handler TIM1_TRG_COM_IRQHandler + add_handler TIM1_CC_IRQHandler + add_handler TIM2_IRQHandler + add_handler TIM3_IRQHandler + add_handler TIM4_IRQHandler + add_handler TIM5_IRQHandler + add_handler TIM6_IRQHandler + add_handler TIM7_IRQHandler + add_handler TIM8_BRK_IRQHandler + add_handler TIM8_UP_IRQHandler + add_handler TIM8_TRG_COM_IRQHandler + add_handler TIM8_CC_IRQHandler + add_handler I2C1_EV_IRQHandler + add_handler I2C1_ER_IRQHandler + add_handler I2C2_EV_IRQHandler + add_handler I2C2_ER_IRQHandler + add_handler SPI1_IRQHandler + add_handler SPI2_IRQHandler + add_handler USART1_IRQHandler + add_handler USART2_IRQHandler + add_handler USART3_IRQHandler + add_handler UART4_IRQHandler + add_handler UART5_IRQHandler + add_handler LPUART1_IRQHandler + add_handler LPTIM1_IRQHandler + add_handler LPTIM2_IRQHandler + add_handler TIM15_IRQHandler + add_handler TIM16_IRQHandler + add_handler TIM17_IRQHandler + add_handler COMP_IRQHandler + add_handler OTG_HS_IRQHandler + add_handler CRS_IRQHandler + add_handler FMC_IRQHandler + add_handler OCTOSPI1_IRQHandler + add_handler PWR_S3WU_IRQHandler + add_handler SDMMC1_IRQHandler + add_handler SDMMC2_IRQHandler + add_handler GPDMA1_Channel8_IRQHandler + add_handler GPDMA1_Channel9_IRQHandler + add_handler GPDMA1_Channel10_IRQHandler + add_handler GPDMA1_Channel11_IRQHandler + add_handler GPDMA1_Channel12_IRQHandler + add_handler GPDMA1_Channel13_IRQHandler + add_handler GPDMA1_Channel14_IRQHandler + add_handler GPDMA1_Channel15_IRQHandler + add_handler I2C3_EV_IRQHandler + add_handler I2C3_ER_IRQHandler + add_handler SAI1_IRQHandler + add_handler SAI2_IRQHandler + add_handler TSC_IRQHandler + add_handler AES_IRQHandler + add_handler RNG_IRQHandler + add_handler FPU_IRQHandler + add_handler HASH_IRQHandler + add_handler PKA_IRQHandler + add_handler LPTIM3_IRQHandler + add_handler SPI3_IRQHandler + add_handler I2C4_ER_IRQHandler + add_handler I2C4_EV_IRQHandler + add_handler MDF1_FLT0_IRQHandler + add_handler MDF1_FLT1_IRQHandler + add_handler MDF1_FLT2_IRQHandler + add_handler MDF1_FLT3_IRQHandler + add_handler UCPD1_IRQHandler + add_handler ICACHE_IRQHandler + add_handler OTFDEC1_IRQHandler + add_handler OTFDEC2_IRQHandler + add_handler LPTIM4_IRQHandler + add_handler DCACHE1_IRQHandler + add_handler ADF1_IRQHandler + add_handler ADC4_IRQHandler + add_handler LPDMA1_Channel0_IRQHandler + add_handler LPDMA1_Channel1_IRQHandler + add_handler LPDMA1_Channel2_IRQHandler + add_handler LPDMA1_Channel3_IRQHandler + add_handler DMA2D_IRQHandler + add_handler DCMI_PSSI_IRQHandler + add_handler OCTOSPI2_IRQHandler + add_handler MDF1_FLT4_IRQHandler + add_handler MDF1_FLT5_IRQHandler + add_handler CORDIC_IRQHandler + add_handler FMAC_IRQHandler + add_handler LSECSSD_IRQHandler + add_handler USART6_IRQHandler + add_handler I2C5_ER_IRQHandler + add_handler I2C5_EV_IRQHandler + add_handler I2C6_ER_IRQHandler + add_handler I2C6_EV_IRQHandler + add_handler HSPI1_IRQHandler + add_handler GPU2D_IRQHandler + add_handler GPU2D_ER_IRQHandler + add_handler GFXMMU_IRQHandler + add_handler LTDC_IRQHandler + add_handler LTDC_ER_IRQHandler + add_handler DSI_IRQHandler + add_handler DCACHE2_IRQHandler + + .end diff --git a/core/embed/trezorhal/tamper.h b/core/embed/trezorhal/tamper.h new file mode 100644 index 00000000000..5d3fe12b092 --- /dev/null +++ b/core/embed/trezorhal/tamper.h @@ -0,0 +1,38 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#ifndef TREZOR_HAL_TAMPER_H +#define TREZOR_HAL_TAMPER_H + +#include + +// Tamper module enables the internal tamper detection on STM32 microcontroller +// as well as external tamper input if it's available on the device + +// Initializes the tamper detection +void tamper_init(void); + +// Triggers one of internal tampers. +// The function is intended for experimentation with internal tamper mechanism +// Use TAMP_CR1_xxx constants to as a parameter +// Only TAMP_CR1_ITAMP5E (RTC) and TAMP_CR1_ITAMP8E (monotonic counter) +// are supported +void tamper_test(uint32_t tamper_type); + +#endif // TREZOR_HAL_TAMPER_H diff --git a/core/embed/trezorhal/touch.h b/core/embed/trezorhal/touch.h index 389c8a03f0a..d56c2e4ee1d 100644 --- a/core/embed/trezorhal/touch.h +++ b/core/embed/trezorhal/touch.h @@ -10,6 +10,8 @@ void touch_init(void); void touch_power_on(void); void touch_power_off(void); +void touch_wait_until_ready(void); + void touch_sensitivity(uint8_t value); uint32_t touch_read(void); uint32_t touch_click(void); diff --git a/core/embed/trezorhal/trustzone.h b/core/embed/trezorhal/trustzone.h new file mode 100644 index 00000000000..a132bcb6b8e --- /dev/null +++ b/core/embed/trezorhal/trustzone.h @@ -0,0 +1,31 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#ifndef __TREZORHAL_TRUSTZONE__ +#define __TREZORHAL_TRUSTZONE__ + +#ifdef BOARDLOADER + +// Provides initial security configuration of CPU and GTZC +// in the board-loader +void trustzone_init_boardloader(void); + +#endif // BOARDLOADER + +#endif diff --git a/core/embed/trezorhal/unix/boot_args.c b/core/embed/trezorhal/unix/boot_args.c new file mode 100644 index 00000000000..b9765d43e02 --- /dev/null +++ b/core/embed/trezorhal/unix/boot_args.c @@ -0,0 +1,44 @@ + +#include "../boot_args.h" +#include +#include + +// The 'g_boot_command_shadow' variable stores the 'command' for the next +// reboot/jumping to the bootloadeer. It may be one of the +// 'BOOT_COMMAND_xxx' values defined in the enumeration, or it could +// be any other value that should be treated as a non-special action, +// in which case the bootloader should behave as if the device was +// just powered up. + +static boot_command_t g_boot_command_shadow; + +// The 'g_boot_args' array stores extra arguments passed +// function boot_args. It sits at section that persists jump to the bootloader. +static boot_args_t g_boot_args; + +void bootargs_set(boot_command_t command, const void* args, size_t args_size) { + // save boot command + g_boot_command_shadow = command; + + size_t copy_size = 0; + // copy arguments up to BOOT_ARGS_MAX_SIZE + if (args != NULL && args_size > 0) { + copy_size = MIN(args_size, BOOT_ARGS_MAX_SIZE); + memcpy(&g_boot_args.raw[0], args, copy_size); + } + + // clear rest of boot_args array + size_t clear_size = BOOT_ARGS_MAX_SIZE - copy_size; + if (clear_size > 0) { + memset(&g_boot_args.raw[copy_size], 0, clear_size); + } +} + +void bootargs_clear() { + g_boot_command_shadow = BOOT_COMMAND_NONE; + memset(&g_boot_args, 0, sizeof(g_boot_args)); +} + +boot_command_t bootargs_get_command() { return g_boot_command_shadow; } + +const boot_args_t* bootargs_get_args() { return &g_boot_args; } diff --git a/core/embed/trezorhal/unix/fault_handlers.c b/core/embed/trezorhal/unix/fault_handlers.c new file mode 100644 index 00000000000..1e7754849cc --- /dev/null +++ b/core/embed/trezorhal/unix/fault_handlers.c @@ -0,0 +1,22 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include + +void fault_handlers_init(void) {} diff --git a/core/embed/trezorhal/unix/flash.c b/core/embed/trezorhal/unix/flash.c index 60f3ae7b030..ee58ceb3d13 100644 --- a/core/embed/trezorhal/unix/flash.c +++ b/core/embed/trezorhal/unix/flash.c @@ -80,11 +80,6 @@ static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { static uint8_t *FLASH_BUFFER = NULL; static uint32_t FLASH_SIZE; -#define OTP_BLOCK_SIZE 32 -#define FLASH_SECTOR_OTP (FLASH_SECTOR_COUNT) - -static uint8_t OTP_BUFFER[OTP_BLOCK_SIZE * 64]; - static void flash_exit(void) { int r = munmap(FLASH_BUFFER, FLASH_SIZE); ensure(sectrue * (r == 0), "munmap failed"); @@ -123,9 +118,6 @@ void flash_init(void) { FLASH_BUFFER = (uint8_t *)map; - // fill OTP buffer with ones - memset(OTP_BUFFER, 0xFF, sizeof(OTP_BUFFER)); - atexit(flash_exit); } @@ -145,79 +137,44 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) { return FLASH_BUFFER + addr - FLASH_SECTOR_TABLE[0]; } -uint32_t flash_sector_size(uint16_t sector) { - if (sector >= FLASH_SECTOR_COUNT) { +uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) { + if (first_sector + sector_count > FLASH_SECTOR_COUNT) { return 0; } - return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + return FLASH_SECTOR_TABLE[first_sector + sector_count] - + FLASH_SECTOR_TABLE[first_sector]; } -secbool flash_area_erase_bulk(const flash_area_t *area, int count, - void (*progress)(int pos, int len)) { - ensure(flash_unlock_write(), NULL); +uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) { + uint16_t sector = first_sector; - int total_sectors = 0; - int done_sectors = 0; - for (int a = 0; a < count; a++) { - for (int i = 0; i < area[a].num_subareas; i++) { - total_sectors += area[a].subarea[i].num_sectors; - } - } - - if (progress) { - progress(0, total_sectors); - } + while (sector < FLASH_SECTOR_COUNT) { + uint32_t sector_size = + FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; - for (int a = 0; a < count; a++) { - for (int s = 0; s < area[a].num_subareas; s++) { - for (int i = 0; i < area[a].subarea[s].num_sectors; i++) { - int sector = area[a].subarea[s].first_sector + i; - - const uint32_t offset = - FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0]; - const uint32_t size = - FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; - memset(FLASH_BUFFER + offset, 0xFF, size); - - done_sectors++; - if (progress) { - progress(done_sectors, total_sectors); - } - } + if (offset < sector_size) { + break; } + offset -= sector_size; + sector++; } - ensure(flash_lock_write(), NULL); - return sectrue; + + return sector; } -secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset, - uint32_t *bytes_erased) { - uint32_t sector_offset = 0; - *bytes_erased = 0; - - for (int s = 0; s < area->num_subareas; s++) { - for (int i = 0; i < area->subarea[s].num_sectors; i++) { - uint32_t sector_index = area->subarea[s].first_sector + i; - uint32_t sector_size = FLASH_SECTOR_TABLE[sector_index + 1] - - FLASH_SECTOR_TABLE[sector_index]; - - if (offset == sector_offset) { - uint8_t *flash = - (uint8_t *)flash_get_address(sector_index, 0, sector_size); - memset(flash, 0xFF, sector_size); - *bytes_erased = sector_size; - return sectrue; - } - - sector_offset += sector_size; - } +secbool flash_sector_erase(uint16_t sector) { + if (sector >= FLASH_SECTOR_COUNT) { + return secfalse; } - if (offset == sector_offset) { - return sectrue; - } + const uint32_t offset = FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0]; + + const uint32_t size = + FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + + memset(FLASH_BUFFER + offset, 0xFF, size); - return secfalse; + return sectrue; } secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) { @@ -261,33 +218,3 @@ secbool flash_write_block(uint16_t sector, uint32_t offset, } return sectrue; } - -secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, - uint8_t datalen) { - if (offset + datalen > OTP_BLOCK_SIZE) { - return secfalse; - } - uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset; - memcpy(data, OTP_BUFFER + offset_in_sector, datalen); - return sectrue; -} - -secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, - uint8_t datalen) { - if (offset + datalen > OTP_BLOCK_SIZE) { - return secfalse; - } - uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset; - uint8_t *flash = OTP_BUFFER + offset_in_sector; - for (int i = 0; i < datalen; i++) { - if ((flash[i] & data[i]) != data[i]) { - return secfalse; // we cannot change zeroes to ones - } - flash[i] = data[i]; - } - return sectrue; -} - -secbool flash_otp_lock(uint8_t block) { return secfalse; } - -secbool flash_otp_is_locked(uint8_t block) { return secfalse; } diff --git a/core/embed/trezorhal/unix/flash_otp.c b/core/embed/trezorhal/unix/flash_otp.c new file mode 100644 index 00000000000..1369e092937 --- /dev/null +++ b/core/embed/trezorhal/unix/flash_otp.c @@ -0,0 +1,62 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include + +#include "../flash_otp.h" + +#define OTP_BLOCK_SIZE 32 +#define FLASH_SECTOR_OTP (FLASH_SECTOR_COUNT) + +static uint8_t OTP_BUFFER[OTP_BLOCK_SIZE * 64]; + +void flash_otp_init(void) { + // fill OTP buffer with ones + memset(OTP_BUFFER, 0xFF, sizeof(OTP_BUFFER)); +} + +secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, + uint8_t datalen) { + if (offset + datalen > OTP_BLOCK_SIZE) { + return secfalse; + } + uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset; + memcpy(data, OTP_BUFFER + offset_in_sector, datalen); + return sectrue; +} + +secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, + uint8_t datalen) { + if (offset + datalen > OTP_BLOCK_SIZE) { + return secfalse; + } + uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset; + uint8_t *flash = OTP_BUFFER + offset_in_sector; + for (int i = 0; i < datalen; i++) { + if ((flash[i] & data[i]) != data[i]) { + return secfalse; // we cannot change zeroes to ones + } + flash[i] = data[i]; + } + return sectrue; +} + +secbool flash_otp_lock(uint8_t block) { return secfalse; } + +secbool flash_otp_is_locked(uint8_t block) { return secfalse; } diff --git a/core/embed/trezorhal/unix/platform.h b/core/embed/trezorhal/unix/platform.h index 0cab1411c1c..29f0a4ddd5f 100644 --- a/core/embed/trezorhal/unix/platform.h +++ b/core/embed/trezorhal/unix/platform.h @@ -1,2 +1,4 @@ +#define SENSITIVE + void emulator_poll_events(void); diff --git a/core/embed/trezorhal/unix/touch/touch.c b/core/embed/trezorhal/unix/touch/touch.c index 56e617854b7..cfb49599f1d 100644 --- a/core/embed/trezorhal/unix/touch/touch.c +++ b/core/embed/trezorhal/unix/touch/touch.c @@ -84,6 +84,7 @@ uint32_t touch_read(void) { void touch_init(void) {} void touch_power_on(void) {} +void touch_wait_until_ready(void) {} uint32_t touch_is_detected(void) { return _touch_detected; } diff --git a/core/embed/trezorhal/unix/translations.c b/core/embed/trezorhal/unix/translations.c deleted file mode 120000 index 21b03004c79..00000000000 --- a/core/embed/trezorhal/unix/translations.c +++ /dev/null @@ -1 +0,0 @@ -../stm32f4/translations.c \ No newline at end of file diff --git a/core/embed/unix/main.c b/core/embed/unix/main.c index a6c90fe414f..f7c6461ea8d 100644 --- a/core/embed/unix/main.c +++ b/core/embed/unix/main.c @@ -40,6 +40,7 @@ #include "extmod/misc.h" #include "extmod/vfs_posix.h" #include "flash.h" +#include "flash_otp.h" #include "genhdr/mpversion.h" #include "input.h" #include "py/builtin.h" @@ -482,6 +483,7 @@ MP_NOINLINE int main_(int argc, char **argv) { // Map trezor.flash to memory. flash_init(); + flash_otp_init(); #if MICROPY_ENABLE_GC char *heap = malloc(heap_size); diff --git a/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.json b/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.json new file mode 100644 index 00000000000..d4483d0867c --- /dev/null +++ b/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.json @@ -0,0 +1,20 @@ +{ + "header_len": 4608, + "text": "DEV ONLY, DO NOT USE!", + "hw_model": "D002", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": true, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.toif b/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.toif new file mode 100644 index 00000000000..3b187a7006f Binary files /dev/null and b/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.toif differ diff --git a/core/embed/vendorheader/D002/vendor_unsafe.json b/core/embed/vendorheader/D002/vendor_unsafe.json new file mode 100644 index 00000000000..500fcb84e28 --- /dev/null +++ b/core/embed/vendorheader/D002/vendor_unsafe.json @@ -0,0 +1,20 @@ +{ + "header_len": 4608, + "text": "UNSAFE, DO NOT USE!", + "hw_model": "D002", + "expiry": 0, + "version": [0, 1], + "sig_m": 2, + "trust": { + "allow_run_with_secret": false, + "show_vendor_string": true, + "require_user_click": true, + "red_background": true, + "delay": 1 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/vendorheader/D002/vendor_unsafe.toif b/core/embed/vendorheader/D002/vendor_unsafe.toif new file mode 100644 index 00000000000..8c25f0ddd9f Binary files /dev/null and b/core/embed/vendorheader/D002/vendor_unsafe.toif differ diff --git a/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin new file mode 100644 index 00000000000..e338b2d0981 Binary files /dev/null and b/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin differ diff --git a/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_unsigned.bin new file mode 100644 index 00000000000..151fccf6f53 Binary files /dev/null and b/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/vendorheader/D002/vendorheader_unsafe_signed_dev.bin b/core/embed/vendorheader/D002/vendorheader_unsafe_signed_dev.bin new file mode 100644 index 00000000000..de32f571afd Binary files /dev/null and b/core/embed/vendorheader/D002/vendorheader_unsafe_signed_dev.bin differ diff --git a/core/embed/vendorheader/D002/vendorheader_unsafe_unsigned.bin b/core/embed/vendorheader/D002/vendorheader_unsafe_unsigned.bin new file mode 100644 index 00000000000..c8f58ec6ffb Binary files /dev/null and b/core/embed/vendorheader/D002/vendorheader_unsafe_unsigned.bin differ diff --git a/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.json b/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.json new file mode 100644 index 00000000000..d4854f27f1f --- /dev/null +++ b/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.json @@ -0,0 +1,20 @@ +{ + "header_len": 4608, + "text": "DEV ONLY, DO NOT USE!", + "hw_model": "T3T1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": true, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.toif b/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.toif new file mode 100644 index 00000000000..231990e5a2e Binary files /dev/null and b/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.toif differ diff --git a/core/embed/vendorheader/T3T1/vendor_unsafe.json b/core/embed/vendorheader/T3T1/vendor_unsafe.json new file mode 100644 index 00000000000..b9f1bda48c0 --- /dev/null +++ b/core/embed/vendorheader/T3T1/vendor_unsafe.json @@ -0,0 +1,20 @@ +{ + "header_len": 4608, + "text": "UNSAFE, DO NOT USE!", + "hw_model": "T3T1", + "expiry": 0, + "version": [0, 1], + "sig_m": 2, + "trust": { + "allow_run_with_secret": false, + "show_vendor_string": true, + "require_user_click": true, + "red_background": true, + "delay": 1 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/vendorheader/T3T1/vendor_unsafe.toif b/core/embed/vendorheader/T3T1/vendor_unsafe.toif new file mode 100644 index 00000000000..3b187a7006f Binary files /dev/null and b/core/embed/vendorheader/T3T1/vendor_unsafe.toif differ diff --git a/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin new file mode 100644 index 00000000000..81e72d1576d Binary files /dev/null and b/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin differ diff --git a/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin new file mode 100644 index 00000000000..577f6dd6ea4 Binary files /dev/null and b/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/vendorheader/T3T1/vendorheader_unsafe_signed_dev.bin b/core/embed/vendorheader/T3T1/vendorheader_unsafe_signed_dev.bin new file mode 100644 index 00000000000..a906b958185 Binary files /dev/null and b/core/embed/vendorheader/T3T1/vendorheader_unsafe_signed_dev.bin differ diff --git a/core/embed/vendorheader/T3T1/vendorheader_unsafe_unsigned.bin b/core/embed/vendorheader/T3T1/vendorheader_unsafe_unsigned.bin new file mode 100644 index 00000000000..9818e318ec9 Binary files /dev/null and b/core/embed/vendorheader/T3T1/vendorheader_unsafe_unsigned.bin differ diff --git a/core/embed/vendorheader/generate.sh b/core/embed/vendorheader/generate.sh index 7dc1a264fa1..14a9b1fe221 100755 --- a/core/embed/vendorheader/generate.sh +++ b/core/embed/vendorheader/generate.sh @@ -16,7 +16,7 @@ for arg in "$@"; do fi done -MODELS=(T2T1 T2B1 D001) +MODELS=(T2T1 T2B1 T3T1 D001 D002) for MODEL in ${MODELS[@]}; do cd $MODEL diff --git a/core/mocks/generated/trezorutils.pyi b/core/mocks/generated/trezorutils.pyi index 4ba9cdbf280..94dc4d6de37 100644 --- a/core/mocks/generated/trezorutils.pyi +++ b/core/mocks/generated/trezorutils.pyi @@ -74,6 +74,13 @@ def unit_btconly() -> bool | None: """ +# extmod/modtrezorutils/modtrezorutils.c +def sd_hotswap_enabled() -> bool: + """ + Returns True if SD card hot swapping is enabled + """ + + # extmod/modtrezorutils/modtrezorutils.c def reboot_to_bootloader( boot_command : int = 0, diff --git a/core/site_scons/boards/discovery2.py b/core/site_scons/boards/discovery2.py new file mode 100644 index 00000000000..5a7c2d32a11 --- /dev/null +++ b/core/site_scons/boards/discovery2.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +from . import get_hw_model_as_number +from .stm32u5_common import stm32u5_common_files + + +def configure( + env: dict, + features_wanted: list[str], + defines: list[str | tuple[str, str]], + sources: list[str], + paths: list[str], +) -> list[str]: + features_available: list[str] = [] + board = "stm32u5a9j-dk.h" + display = "dsi.c" + hw_model = get_hw_model_as_number("D002") + hw_revision = 0 + + mcu = "STM32U5A9xx" + linker_script = "stm32u5a" + + stm32u5_common_files(env, defines, sources, paths) + + env.get("ENV")[ + "CPU_ASFLAGS" + ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 " + env.get("ENV")[ + "CPU_CCFLAGS" + ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 -mcmse " + env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf" + + defines += [mcu] + defines += [ + f'TREZOR_BOARD=\\"boards/{board}\\"', + ] + defines += [ + f"HW_MODEL={hw_model}", + ] + defines += [ + f"HW_REVISION={hw_revision}", + ] + sources += [ + "embed/models/model_D002_layout.c", + ] + sources += [ + f"embed/trezorhal/stm32u5/displays/{display}", + ] + + if "input" in features_wanted: + sources += [ + "embed/trezorhal/stm32u5/i2c.c", + ] + sources += [ + "embed/lib/touch.c", + ] + sources += [ + "embed/trezorhal/stm32u5/touch/sitronix.c", + ] + features_available.append("touch") + + # if "sd_card" in features_wanted: + # sources += ['embed/trezorhal/sdcard.c', ] + # sources += ['embed/extmod/modtrezorio/ff.c', ] + # sources += ['embed/extmod/modtrezorio/ffunicode.c', ] + # features_available.append("sd_card") + + if "sbu" in features_wanted: + sources += [ + "embed/trezorhal/stm32u5/sbu.c", + ] + features_available.append("sbu") + + if "usb" in features_wanted: + sources += [ + "embed/trezorhal/stm32u5/usb.c", + "embed/trezorhal/stm32u5/usbd_conf.c", + "embed/trezorhal/stm32u5/usbd_core.c", + "embed/trezorhal/stm32u5/usbd_ctlreq.c", + "embed/trezorhal/stm32u5/usbd_ioreq.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_usb.c", + ] + features_available.append("usb") + + defines += ["USE_DMA2D", "FRAMEBUFFER", "FRAMEBUFFER32BIT"] + sources += [ + "embed/trezorhal/stm32u5/dma2d.c", + ] + features_available.append("dma2d") + features_available.append("framebuffer") + features_available.append("framebuffer32bit") + + env.get("ENV")["TREZOR_BOARD"] = board + env.get("ENV")["MCU_TYPE"] = mcu + env.get("ENV")["LINKER_SCRIPT"] = linker_script + + defs = env.get("CPPDEFINES_IMPLICIT") + defs += ["__ARM_FEATURE_CMSE=3"] + + return features_available diff --git a/core/site_scons/boards/stm32f4_common.py b/core/site_scons/boards/stm32f4_common.py index 8f4ccc8cfc0..c9d83588cfa 100644 --- a/core/site_scons/boards/stm32f4_common.py +++ b/core/site_scons/boards/stm32f4_common.py @@ -10,6 +10,7 @@ def stm32f4_common_files(env, defines, sources, paths): paths += [ "embed/trezorhal/stm32f4", + "vendor/micropython/lib/cmsis/inc", "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc", "vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include", ] @@ -39,8 +40,11 @@ def stm32f4_common_files(env, defines, sources, paths): sources += [ "embed/trezorhal/stm32f4/board_capabilities.c", + "embed/trezorhal/stm32f4/boot_args.c", "embed/trezorhal/stm32f4/common.c", + "embed/trezorhal/stm32f4/fault_handlers.c", "embed/trezorhal/stm32f4/flash.c", + "embed/trezorhal/stm32f4/flash_otp.c", "embed/trezorhal/stm32f4/lowlevel.c", "embed/trezorhal/stm32f4/mpu.c", "embed/trezorhal/stm32f4/platform.c", @@ -49,7 +53,6 @@ def stm32f4_common_files(env, defines, sources, paths): "embed/trezorhal/stm32f4/random_delays.c", "embed/trezorhal/stm32f4/rng.c", "embed/trezorhal/stm32f4/vectortable.s", - "embed/trezorhal/stm32f4/translations.c", ] # boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks @@ -68,7 +71,12 @@ def stm32f4_common_files(env, defines, sources, paths): "-I../trezorhal/stm32f4;" "-I../../vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc;" "-I../../vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include;" + "-I../../vendor/micropython/lib/cmsis/inc;" "-DSTM32_HAL_H=;" + "-DSTM32F4;" "-DFLASH_BLOCK_WORDS=1;" "-DFLASH_BIT_ACCESS=1" ) + + env.get("ENV")["SUFFIX"] = "stm32f4" + env.get("ENV")["LINKER_SCRIPT"] = "stm32f4" diff --git a/core/site_scons/boards/stm32u5_common.py b/core/site_scons/boards/stm32u5_common.py new file mode 100644 index 00000000000..2ddf6c808d2 --- /dev/null +++ b/core/site_scons/boards/stm32u5_common.py @@ -0,0 +1,93 @@ +from __future__ import annotations + + +def stm32u5_common_files(env, defines, sources, paths): + defines += [ + ("STM32_HAL_H", '""'), + ("FLASH_BLOCK_WORDS", "4"), + ] + + paths += [ + "embed/trezorhal/stm32u5", + "vendor/stm32u5xx_hal_driver/Inc", + "vendor/cmsis_device_u5/Include", + "vendor/cmsis_5/CMSIS/Core/Include", + ] + + sources += [ + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_cortex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_cryp.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_dma2d.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_dma.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_dma_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_dsi.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_flash.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_flash_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_gfxmmu.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_gpio.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_gtzc.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_hash.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_hash_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_i2c.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_i2c_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_icache.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_ltdc.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_ltdc_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_pcd.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_pcd_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_pwr.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_pwr_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_rcc.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_rcc_ex.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_rtc.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_spi.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_sram.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_fmc.c", + ] + + sources += [ + "embed/trezorhal/stm32u5/board_capabilities.c", + "embed/trezorhal/stm32u5/boot_args.c", + "embed/trezorhal/stm32u5/common.c", + "embed/trezorhal/stm32u5/fault_handlers.c", + "embed/trezorhal/stm32u5/flash.c", + "embed/trezorhal/stm32u5/flash_otp.c", + "embed/trezorhal/stm32u5/lowlevel.c", + "embed/trezorhal/stm32u5/hash_processor.c", + "embed/trezorhal/stm32u5/mpu.c", + "embed/trezorhal/stm32u5/platform.c", + "embed/trezorhal/stm32u5/secret.c", + "embed/trezorhal/stm32u5/secure_aes.c", + "embed/trezorhal/stm32u5/systick.c", + "embed/trezorhal/stm32f4/supervise.c", + "embed/trezorhal/stm32u5/random_delays.c", + "embed/trezorhal/stm32u5/rng.c", + "embed/trezorhal/stm32u5/tamper.c", + "embed/trezorhal/stm32u5/trustzone.c", + "embed/trezorhal/stm32u5/vectortable.s", + ] + + # boardloader needs separate assembler for some function unencumbered by various FW+bootloader hacks + # this helps to prevent making a bug in boardloader which may be hard to fix since it's locked with write-protect + env_constraints = env.get("CONSTRAINTS") + if env_constraints and "limited_util_s" in env_constraints: + sources += [ + "embed/trezorhal/stm32u5/limited_util.s", + ] + else: + sources += [ + "embed/trezorhal/stm32u5/util.s", + ] + + env.get("ENV")["RUST_INCLUDES"] = ( + "-I../trezorhal/stm32u5;" + "-I../../vendor/stm32u5xx_hal_driver/Inc;" + "-I../../vendor/cmsis_device_u5/Include;" + "-I../../vendor/cmsis_5/CMSIS/Core/Include;" + "-DSTM32_HAL_H=;" + "-DSTM32U5;" + "-DFLASH_BLOCK_WORDS=4" + ) + + env.get("ENV")["SUFFIX"] = "stm32u5" diff --git a/core/site_scons/boards/trezor_t3t1_v4.py b/core/site_scons/boards/trezor_t3t1_v4.py new file mode 100644 index 00000000000..7e18d2586d2 --- /dev/null +++ b/core/site_scons/boards/trezor_t3t1_v4.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +from . import get_hw_model_as_number +from .stm32u5_common import stm32u5_common_files + + +def configure( + env: dict, + features_wanted: list[str], + defines: list[str | tuple[str, str]], + sources: list[str], + paths: list[str], +) -> list[str]: + features_available: list[str] = [] + board = "trezor_t3t1_v4.h" + display = "st7789v.c" + hw_model = get_hw_model_as_number("T3T1") + hw_revision = 0 + features_available.append("disp_i8080_8bit_dw") + + mcu = "STM32U585xx" + linker_script = "stm32u58" + + stm32u5_common_files(env, defines, sources, paths) + + env.get("ENV")[ + "CPU_ASFLAGS" + ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 " + env.get("ENV")[ + "CPU_CCFLAGS" + ] = "-mthumb -mcpu=cortex-m33 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -mtune=cortex-m33 -mcmse " + env.get("ENV")["RUST_TARGET"] = "thumbv8m.main-none-eabihf" + + defines += [mcu] + defines += [f'TREZOR_BOARD=\\"boards/{board}\\"'] + defines += [f"HW_MODEL={hw_model}"] + defines += [f"HW_REVISION={hw_revision}"] + sources += [ + "embed/models/model_T3T1_layout.c", + ] + sources += [f"embed/trezorhal/stm32u5/displays/{display}"] + sources += ["embed/trezorhal/stm32u5/backlight_pwm.c"] + sources += [ + "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c", + ] + + features_available.append("backlight") + + if "input" in features_wanted: + sources += ["embed/trezorhal/stm32u5/i2c.c"] + sources += ["embed/trezorhal/stm32u5/touch/ft6x36.c"] + sources += ["embed/lib/touch.c"] + features_available.append("touch") + + if "haptic" in features_wanted: + sources += [ + "embed/trezorhal/stm32u5/haptic/drv2625/drv2625.c", + ] + sources += [ + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_tim.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_tim_ex.c", + ] + features_available.append("haptic") + + if "sd_card" in features_wanted: + sources += ["embed/trezorhal/stm32u5/sdcard.c"] + sources += ["embed/trezorhal/stm32u5/stm32u5xx_hal_sd.c"] + sources += ["embed/extmod/modtrezorio/ff.c"] + sources += ["embed/extmod/modtrezorio/ffunicode.c"] + features_available.append("sd_card") + sources += ["vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_sdmmc.c"] + + if "sbu" in features_wanted: + sources += ["embed/trezorhal/stm32u5/sbu.c"] + features_available.append("sbu") + + if "usb" in features_wanted: + sources += [ + "embed/trezorhal/stm32u5/usb.c", + "embed/trezorhal/stm32u5/usbd_conf.c", + "embed/trezorhal/stm32u5/usbd_core.c", + "embed/trezorhal/stm32u5/usbd_ctlreq.c", + "embed/trezorhal/stm32u5/usbd_ioreq.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_ll_usb.c", + ] + features_available.append("usb") + + if "dma2d" in features_wanted: + defines += ["USE_DMA2D"] + sources += ["embed/trezorhal/stm32u5/dma2d.c"] + features_available.append("dma2d") + + if "optiga" in features_wanted: + defines += ["USE_OPTIGA=1"] + sources += ["embed/trezorhal/stm32u5/optiga_hal.c"] + sources += ["embed/trezorhal/optiga/optiga.c"] + sources += ["embed/trezorhal/optiga/optiga_commands.c"] + sources += ["embed/trezorhal/optiga/optiga_transport.c"] + sources += ["vendor/trezor-crypto/hash_to_curve.c"] + features_available.append("optiga") + + env.get("ENV")["TREZOR_BOARD"] = board + env.get("ENV")["MCU_TYPE"] = mcu + env.get("ENV")["LINKER_SCRIPT"] = linker_script + + defs = env.get("CPPDEFINES_IMPLICIT") + defs += ["__ARM_FEATURE_CMSE=3"] + + return features_available diff --git a/core/site_scons/tools.py b/core/site_scons/tools.py index 0cc34f0f266..daf32422299 100644 --- a/core/site_scons/tools.py +++ b/core/site_scons/tools.py @@ -6,12 +6,14 @@ from boards import ( discovery, + discovery2, trezor_1, trezor_r_v3, trezor_r_v4, trezor_r_v6, trezor_r_v10, trezor_t, + trezor_t3t1_v4, ) HERE = Path(__file__).parent.resolve() @@ -57,8 +59,12 @@ def configure_board( elif model_r_version == 10: return trezor_r_v10.configure(env, features_wanted, defines, sources, paths) raise Exception("Unknown model_r_version") + elif model in ("T3T1",): + return trezor_t3t1_v4.configure(env, features_wanted, defines, sources, paths) elif model in ("DISC1",): return discovery.configure(env, features_wanted, defines, sources, paths) + elif model in ("DISC2",): + return discovery2.configure(env, features_wanted, defines, sources, paths) raise Exception("Unknown model") @@ -69,8 +75,12 @@ def get_model_identifier(model: str) -> str: return "T2T1" elif model == "R": return "T2B1" + elif model == "T3T1": + return "T3T1" elif model == "DISC1": return "D001" + elif model == "DISC2": + return "D002" else: raise Exception("Unknown model") diff --git a/core/src/apps/common/sdcard.py b/core/src/apps/common/sdcard.py index c6446e05cd2..e5d0ba96b2f 100644 --- a/core/src/apps/common/sdcard.py +++ b/core/src/apps/common/sdcard.py @@ -1,6 +1,6 @@ -from storage.sd_salt import SD_CARD_HOT_SWAPPABLE from trezor import TR, io, wire from trezor.ui.layouts import confirm_action, show_error_and_raise +from trezor.utils import sd_hotswap_enabled class SdCardUnavailable(wire.ProcessError): @@ -8,7 +8,7 @@ class SdCardUnavailable(wire.ProcessError): async def _confirm_retry_wrong_card() -> None: - if SD_CARD_HOT_SWAPPABLE: + if sd_hotswap_enabled(): await confirm_action( "warning_wrong_sd", TR.sd_card__title, @@ -28,7 +28,7 @@ async def _confirm_retry_wrong_card() -> None: async def _confirm_retry_insert_card() -> None: - if SD_CARD_HOT_SWAPPABLE: + if sd_hotswap_enabled(): await confirm_action( "warning_no_sd", TR.sd_card__title, diff --git a/core/src/storage/sd_salt.py b/core/src/storage/sd_salt.py index 2bc8b9b3573..90714436e6d 100644 --- a/core/src/storage/sd_salt.py +++ b/core/src/storage/sd_salt.py @@ -13,7 +13,6 @@ if utils.USE_SD_CARD: fatfs = io.fatfs # global_import_cache -SD_CARD_HOT_SWAPPABLE = False SD_SALT_LEN_BYTES = const(32) _SD_SALT_AUTH_TAG_LEN_BYTES = const(16) diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py index e42d944f23a..15eec59f74c 100644 --- a/core/src/trezor/utils.py +++ b/core/src/trezor/utils.py @@ -20,6 +20,7 @@ halt, memcpy, reboot_to_bootloader, + sd_hotswap_enabled, unit_btconly, unit_color, ) diff --git a/core/tools/combine_firmware b/core/tools/combine_firmware index 046d2f275dd..a1ae841c85b 100755 --- a/core/tools/combine_firmware +++ b/core/tools/combine_firmware @@ -9,12 +9,6 @@ from pathlib import Path import click -BOARDLOADER_START = 0x08000000 -BOARDLOADER_END = 0x0800C000 -BOOTLOADER_START = 0x08020000 -FIRMWARE_START = 0x08040000 - - @click.command() @click.argument( "boardloader", @@ -33,39 +27,75 @@ FIRMWARE_START = 0x08040000 type=click.Path(dir_okay=False, writable=True, path_type=Path), required=False, ) +@click.argument( + "boardloader_start", + type=click.STRING, + required=False, + default="0x08000000", +) +@click.argument( + "boardloader_end", + type=click.STRING, + required=False, + default="0x0800C000", +) +@click.argument( + "bootloader_start", + type=click.STRING, + required=False, + default="0x08020000", +) +@click.argument( + "firmware_start", + type=click.STRING, + required=False, + default="0x08040000", +) def main( - boardloader: Path, bootloader: Path, firmware: Path, outfile: Path | None + boardloader: Path, + bootloader: Path, + firmware: Path, + outfile: Path | None, + boardloader_start: str, + boardloader_end: str, + bootloader_start: str, + firmware_start: str, ) -> None: + boardloader_start = int(boardloader_start, 0) + boardloader_end = int(boardloader_end, 0) + bootloader_start = int(bootloader_start, 0) + firmware_start = int(firmware_start, 0) + if outfile is None: today = datetime.date.today().strftime(r"%Y-%m-%d") outfile = Path(f"combined-{today}.bin") - offset = BOARDLOADER_START + offset = boardloader_start out_bytes = io.BytesIO() # write boardloader offset += out_bytes.write(boardloader.read_bytes()) - if offset > BOARDLOADER_END: + if offset > boardloader_end: raise Exception("Boardloader too big") # zero-pad until next section: - offset += out_bytes.write(b"\x00" * (BOOTLOADER_START - offset)) - assert offset == BOOTLOADER_START + offset += out_bytes.write(b"\x00" * (bootloader_start - offset)) + assert offset == bootloader_start # write bootlaoder offset += out_bytes.write(bootloader.read_bytes()) - if offset > FIRMWARE_START: + if offset > firmware_start: raise Exception("Bootloader too big") # zero-pad until next section: - offset += out_bytes.write(b"\x00" * (FIRMWARE_START - offset)) - assert offset == FIRMWARE_START + offset += out_bytes.write(b"\x00" * (firmware_start - offset)) + assert offset == firmware_start # write firmware offset += out_bytes.write(firmware.read_bytes()) # write out contents - click.echo(f"Writing {outfile} ({offset - BOARDLOADER_START} bytes)") + click.echo(f"Writing {outfile} ({offset - boardloader_start} bytes)") outfile.write_bytes(out_bytes.getvalue()) diff --git a/core/vendor/stm32u5xx_hal_driver b/core/vendor/stm32u5xx_hal_driver new file mode 120000 index 00000000000..f481ba54e6d --- /dev/null +++ b/core/vendor/stm32u5xx_hal_driver @@ -0,0 +1 @@ +../../vendor/stm32u5xx_hal_driver/ \ No newline at end of file diff --git a/docs/core/misc/memory.md b/docs/core/misc/memory.md index 1f1c595d953..55cec1490d2 100644 --- a/docs/core/misc/memory.md +++ b/docs/core/misc/memory.md @@ -33,7 +33,7 @@ | block | range | size | function |----------|-------------------------|------|-------------------------------- -| block 0 | 0x1FFF7800 - 0x1FFF781F | 32 B | device batch (week of manufacture) +| block 0 | 0x1FFF7800 - 0x1FFF781F | 32 B | device batch: {MODEL_IDENTIFIER}-YYMMDD | block 1 | 0x1FFF7820 - 0x1FFF783F | 32 B | bootloader downgrade protection | block 2 | 0x1FFF7840 - 0x1FFF785F | 32 B | vendor keys lock | block 3 | 0x1FFF7860 - 0x1FFF787F | 32 B | entropy/randomness diff --git a/legacy/Makefile b/legacy/Makefile index 0a9354e036d..d77354a04e9 100644 --- a/legacy/Makefile +++ b/legacy/Makefile @@ -20,7 +20,7 @@ OBJS += usb_standard.o OBJS += util.o OBJS += webusb.o OBJS += winusb.o -OBJS += vendor/trezor-storage/flash_common.o +OBJS += vendor/trezor-storage/flash_area.o libtrezor.a: $(OBJS) diff --git a/legacy/flash.c b/legacy/flash.c index e019079a2dc..37a9f62d3b0 100644 --- a/legacy/flash.c +++ b/legacy/flash.c @@ -22,6 +22,7 @@ #include "common.h" #include "flash.h" +#include "flash_area.h" #include "memory.h" #include "supervise.h" @@ -88,11 +89,29 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) { return (const void *)FLASH_PTR(addr); } -uint32_t flash_sector_size(uint16_t sector) { - if (sector >= FLASH_SECTOR_COUNT) { +uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) { + if (first_sector + sector_count >= FLASH_SECTOR_COUNT) { return 0; } - return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + return FLASH_SECTOR_TABLE[first_sector + sector_count] - + FLASH_SECTOR_TABLE[first_sector]; +} + +uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) { + uint16_t sector = first_sector; + + while (sector < FLASH_SECTOR_COUNT) { + uint32_t sector_size = + FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + + if (offset < sector_size) { + break; + } + offset -= sector_size; + sector++; + } + + return sector; } secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) { @@ -144,42 +163,7 @@ secbool flash_write_block(uint16_t sector, uint32_t offset, return flash_write_word(sector, offset, block[0]); } -secbool flash_area_erase_bulk(const flash_area_t *area, int count, - void (*progress)(int pos, int len)) { - ensure(flash_unlock_write(), NULL); - - int total_sectors = 0; - int done_sectors = 0; - for (int a = 0; a < count; a++) { - for (int i = 0; i < area[a].num_subareas; i++) { - total_sectors += area[a].subarea[i].num_sectors; - } - } - if (progress) { - progress(0, total_sectors); - } - - for (int a = 0; a < count; a++) { - for (int s = 0; s < area[a].num_subareas; s++) { - for (int i = 0; i < area[a].subarea[s].num_sectors; i++) { - int sector = area[a].subarea[s].first_sector + i; - svc_flash_erase_sector(sector); - // check whether the sector was really deleted (contains only 0xFF) - const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], - addr_end = FLASH_SECTOR_TABLE[sector + 1]; - for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { - if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { - ensure(flash_lock_write(), NULL); - return secfalse; - } - } - done_sectors++; - if (progress) { - progress(done_sectors, total_sectors); - } - } - } - } - ensure(flash_lock_write(), NULL); +secbool flash_sector_erase(uint16_t sector) { + svc_flash_erase_sector(sector); return sectrue; } diff --git a/legacy/flash.h b/legacy/flash.h index 9ea50d717bc..b7d3c4a376b 100644 --- a/legacy/flash.h +++ b/legacy/flash.h @@ -26,7 +26,7 @@ #define FLASH_SECTOR_COUNT 24 -#include "flash_common.h" +#include "flash_ll.h" // note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) // (reference RM0090 section 3.7.5) diff --git a/legacy/intermediate_fw/trezor.c b/legacy/intermediate_fw/trezor.c index 18d3e9a1292..8f0d9866c05 100644 --- a/legacy/intermediate_fw/trezor.c +++ b/legacy/intermediate_fw/trezor.c @@ -35,8 +35,6 @@ #include "timer.h" #include "util.h" -const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size); - // legacy storage magic #define LEGACY_STORAGE_SECTOR 2 static const uint32_t META_MAGIC_V10 = 0x525a5254; // 'TRZR' diff --git a/legacy/memory.c b/legacy/memory.c index 079ba50413d..a2b16329429 100644 --- a/legacy/memory.c +++ b/legacy/memory.c @@ -28,8 +28,6 @@ #define FLASH_OPTION_BYTES_1 (*(const uint64_t *)0x1FFFC000) #define FLASH_OPTION_BYTES_2 (*(const uint64_t *)0x1FFFC008) -const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size); - void memory_protect(void) { #if PRODUCTION #if BOOTLOADER_QA @@ -110,7 +108,7 @@ int memory_firmware_hash(const uint8_t *challenge, uint32_t challenge_size, } for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - uint32_t size = flash_sector_size(i); + uint32_t size = flash_sector_size(i, 1); const void *data = flash_get_address(i, 0, size); if (data == NULL) { return 1; diff --git a/legacy/norcow_config.h b/legacy/norcow_config.h index 113de9fe0e9..8d37b1bc5e4 100644 --- a/legacy/norcow_config.h +++ b/legacy/norcow_config.h @@ -20,7 +20,7 @@ #ifndef __NORCOW_CONFIG_H__ #define __NORCOW_CONFIG_H__ -#include "flash.h" +#include "flash_area.h" #define NORCOW_SECTOR_COUNT 2 #define NORCOW_SECTOR_SIZE (16 * 1024) diff --git a/python/.changelog.d/3422.added b/python/.changelog.d/3422.added new file mode 100644 index 00000000000..17fb87f4340 --- /dev/null +++ b/python/.changelog.d/3422.added @@ -0,0 +1 @@ +Added support for T3T1 diff --git a/python/src/trezorlib/firmware/models.py b/python/src/trezorlib/firmware/models.py index d70eb996d62..290824db4cc 100644 --- a/python/src/trezorlib/firmware/models.py +++ b/python/src/trezorlib/firmware/models.py @@ -30,14 +30,17 @@ class Model(Enum): T1B1 = b"T1B1" T2T1 = b"T2T1" + T3T1 = b"T3T1" T2B1 = b"T2B1" D001 = b"D001" + D002 = b"D002" # legacy aliases ONE = b"T1B1" T = b"T2T1" R = b"T2B1" DISC1 = b"D001" + DISC2 = b"D002" @classmethod def from_hw_model(cls, hw_model: t.Union["Self", bytes]) -> "Model": @@ -219,6 +222,29 @@ class ModelKeys: firmware_sigs_needed=-1, ) +T3T1 = ModelKeys( + production=False, + boardloader_keys=[ + bytes.fromhex(key) + for key in ( + "db995fe25169d141cab9bbba92baa01f9f2e1ece7df4cb2ac05190f37fcc1f9d", + "2152f8d19b791d24453242e15f2eab6cb7cffa7b6a5ed30097960e069881db12", + "22fc297792f0b6ffc0bfcfdb7edb0c0aa14e025a365ec0e342e86e3829cb74b6", + ) + ], + boardloader_sigs_needed=2, + bootloader_keys=[ + bytes.fromhex(key) + for key in ( + "d759793bbc13a2819a827c76adb6fba8a49aee007f49f2d0992d99b825ad2c48", + "6355691c178a8ff91007a7478afb955ef7352c63e7b25703984cf78b26e21a56", + "ee93a4f66f8d16b819bb9beb9ffccdfcdc1412e87fee6a324c2a99a1e0e67148", + ) + ], + bootloader_sigs_needed=2, + firmware_keys=(), + firmware_sigs_needed=-1, +) LEGACY_HASH_PARAMS = FirmwareHashParameters( hash_function=hashlib.sha256, @@ -232,25 +258,43 @@ class ModelKeys: padding_byte=None, ) +T3T1_HASH_PARAMS = FirmwareHashParameters( + hash_function=hashlib.sha256, + chunk_size=1024 * 128, + padding_byte=None, +) + +D002_HASH_PARAMS = FirmwareHashParameters( + hash_function=hashlib.sha256, + chunk_size=1024 * 256, + padding_byte=None, +) + MODEL_MAP = { Model.T1B1: LEGACY_V3, Model.T2T1: T2T1, Model.T2B1: T2B1, + Model.T3T1: TREZOR_CORE_DEV, Model.D001: TREZOR_CORE_DEV, + Model.D002: TREZOR_CORE_DEV, } MODEL_MAP_DEV = { Model.T1B1: LEGACY_V3_DEV, Model.T2T1: TREZOR_CORE_DEV, Model.T2B1: TREZOR_CORE_DEV, + Model.T3T1: TREZOR_CORE_DEV, Model.D001: TREZOR_CORE_DEV, + Model.D002: TREZOR_CORE_DEV, } MODEL_HASH_PARAMS_MAP = { Model.T1B1: LEGACY_HASH_PARAMS, Model.T2T1: T2T1_HASH_PARAMS, + Model.T3T1: T3T1_HASH_PARAMS, Model.T2B1: T2T1_HASH_PARAMS, Model.D001: T2T1_HASH_PARAMS, + Model.D002: D002_HASH_PARAMS, } # aliases @@ -262,6 +306,7 @@ class ModelKeys: TREZOR_T = T2T1 TREZOR_R = T2B1 +TREZOR_T3T1 = T3T1 TREZOR_T_DEV = TREZOR_CORE_DEV TREZOR_R_DEV = TREZOR_CORE_DEV @@ -269,3 +314,5 @@ class ModelKeys: DISC1_DEV = TREZOR_CORE_DEV D001 = TREZOR_CORE_DEV D001_DEV = TREZOR_CORE_DEV +D002 = TREZOR_CORE_DEV +D002_DEV = TREZOR_CORE_DEV diff --git a/python/src/trezorlib/firmware/vendor.py b/python/src/trezorlib/firmware/vendor.py index a83128f123d..a5a78229396 100644 --- a/python/src/trezorlib/firmware/vendor.py +++ b/python/src/trezorlib/firmware/vendor.py @@ -121,10 +121,11 @@ class VendorHeader(Struct): # fmt: on def digest(self) -> bytes: + hash_function = Model.from_hw_model(self.hw_model).hash_params().hash_function cpy = copy(self) cpy.sigmask = 0 cpy.signature = b"\x00" * 64 - return hashlib.blake2s(cpy.build()).digest() + return hash_function(cpy.build()).digest() def vhash(self) -> bytes: h = hashlib.blake2s() diff --git a/python/src/trezorlib/models.py b/python/src/trezorlib/models.py index af83214a2cb..74b34855d6c 100644 --- a/python/src/trezorlib/models.py +++ b/python/src/trezorlib/models.py @@ -63,6 +63,15 @@ class TrezorModel: default_mapping=mapping.DEFAULT_MAPPING, ) +T3T1 = TrezorModel( + name="T3T1", + internal_name="T3T1", + minimum_version=(2, 1, 0), + vendors=VENDORS, + usb_ids=((0x1209, 0x53C1), (0x1209, 0x53C0)), + default_mapping=mapping.DEFAULT_MAPPING, +) + DISC1 = TrezorModel( name="DISC1", internal_name="D001", @@ -72,15 +81,26 @@ class TrezorModel: default_mapping=mapping.DEFAULT_MAPPING, ) +DISC2 = TrezorModel( + name="DISC2", + internal_name="D002", + minimum_version=(2, 1, 0), + vendors=VENDORS, + usb_ids=((0x1209, 0x53C1), (0x1209, 0x53C0)), + default_mapping=mapping.DEFAULT_MAPPING, +) + # ==== model based names ==== TREZOR_ONE = T1B1 TREZOR_T = T2T1 TREZOR_R = T2B1 TREZOR_SAFE3 = T2B1 +TREZOR_T3T1 = T2B1 TREZOR_DISC1 = DISC1 +TREZOR_DISC2 = DISC2 -TREZORS = {T1B1, T2T1, T2B1, DISC1} +TREZORS = {T1B1, T2T1, T2B1, T3T1, DISC1, DISC2} def by_name(name: Optional[str]) -> Optional[TrezorModel]: diff --git a/storage/flash_area.c b/storage/flash_area.c new file mode 100644 index 00000000000..a979489a9ca --- /dev/null +++ b/storage/flash_area.c @@ -0,0 +1,244 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#include "flash_area.h" +#include + +uint32_t flash_area_get_size(const flash_area_t *area) { + uint32_t size = 0; + for (int i = 0; i < area->num_subareas; i++) { + size += flash_sector_size(area->subarea[i].first_sector, + area->subarea[i].num_sectors); + } + return size; +} + +uint16_t flash_area_total_sectors(const flash_area_t *area) { + uint16_t total = 0; + for (int i = 0; i < area->num_subareas; i++) { + total += area->subarea[i].num_sectors; + } + return total; +} + +static secbool get_sector_and_offset(const flash_area_t *area, uint32_t offset, + uint16_t *sector_out, + uint32_t *offset_out) { + for (int i = 0; i < area->num_subareas; i++) { + // Get the sub-area parameters + uint16_t first_sector = area->subarea[i].first_sector; + uint16_t num_sectors = area->subarea[i].num_sectors; + uint32_t subarea_size = flash_sector_size(first_sector, num_sectors); + // Does the requested offset start in the sub-area? + if (offset < subarea_size) { + uint16_t found_sector = flash_sector_find(first_sector, offset); + *sector_out = found_sector; + *offset_out = + offset - flash_sector_size(first_sector, found_sector - first_sector); + return sectrue; + } + offset -= subarea_size; + } + + return secfalse; +} + +const void *flash_area_get_address(const flash_area_t *area, uint32_t offset, + uint32_t size) { + for (int i = 0; i < area->num_subareas; i++) { + // Get sub-area parameters + uint16_t first_sector = area->subarea[i].first_sector; + uint16_t num_sectors = area->subarea[i].num_sectors; + uint32_t subarea_size = flash_sector_size(first_sector, num_sectors); + // Does the requested block start in the sub-area? + if (offset < subarea_size) { + // Does the requested block fit in the sub-area? + if (offset + size <= subarea_size) { + const uint8_t *ptr = + (const uint8_t *)flash_get_address(first_sector, 0, 0); + // We expect that all sectors/pages in the sub-area make + // a continuous block of adresses with the same security atributes + return ptr + offset; + } else { + return NULL; + } + } + offset -= subarea_size; + } + return NULL; +} + +#if defined FLASH_BIT_ACCESS + +secbool flash_area_write_byte(const flash_area_t *area, uint32_t offset, + uint8_t data) { + uint16_t sector; + uint32_t sector_offset; + if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) { + return secfalse; + } + return flash_write_byte(sector, sector_offset, data); +} + +secbool flash_area_write_word(const flash_area_t *area, uint32_t offset, + uint32_t data) { + uint16_t sector; + uint32_t sector_offset; + if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) { + return secfalse; + } + return flash_write_word(sector, sector_offset, data); +} + +secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset, + const uint32_t *data) { + if (offset % (8 * 16) != 0) { + return secfalse; + } + for (int i = 0; i < (8 * 4); i++) { + if (sectrue != + flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) { + return secfalse; + } + } + return sectrue; +} + +#else // not defined FLASH_BIT_ACCESS + +secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset, + const uint32_t *data) { + uint16_t sector; + uint32_t sector_offset; + if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) { + return secfalse; + } + return flash_write_quadword(sector, sector_offset, data); +} + +secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset, + const uint32_t *data) { + uint16_t sector; + uint32_t sector_offset; + if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) { + return secfalse; + } + return flash_write_burst(sector, sector_offset, data); +} + +#endif // not defined FLASH_BIT_ACCESS + +secbool flash_area_write_block(const flash_area_t *area, uint32_t offset, + const flash_block_t block) { + if (!FLASH_IS_ALIGNED(offset)) { + return secfalse; + } + + uint16_t sector; + uint32_t sector_offset; + if (sectrue != get_sector_and_offset(area, offset, §or, §or_offset)) { + return secfalse; + } + + return flash_write_block(sector, sector_offset, block); +} + +secbool flash_area_erase(const flash_area_t *area, + void (*progress)(int pos, int len)) { + return flash_area_erase_bulk(area, 1, progress); +} + +static secbool erase_sector(uint16_t sector) { + secbool result = secfalse; + + if (sectrue != flash_unlock_write()) { + return secfalse; + } + + result = flash_sector_erase(sector); + + if (sectrue != flash_lock_write()) { + return secfalse; + } + + return result; +} + +secbool flash_area_erase_bulk(const flash_area_t *area, int count, + void (*progress)(int pos, int len)) { + int total_sectors = 0; + int done_sectors = 0; + for (int a = 0; a < count; a++) { + for (int i = 0; i < area[a].num_subareas; i++) { + total_sectors += area[a].subarea[i].num_sectors; + } + } + if (progress) { + progress(0, total_sectors); + } + + for (int a = 0; a < count; a++) { + for (int s = 0; s < area[a].num_subareas; s++) { + for (int i = 0; i < area[a].subarea[s].num_sectors; i++) { + int sector = area[a].subarea[s].first_sector + i; + + if (sectrue != erase_sector(sector)) { + return secfalse; + } + + done_sectors++; + if (progress) { + progress(done_sectors, total_sectors); + } + } + } + } + + return sectrue; +} + +secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset, + uint32_t *bytes_erased) { + uint32_t sector_offset = 0; + *bytes_erased = 0; + + for (int s = 0; s < area->num_subareas; s++) { + for (int i = 0; i < area->subarea[s].num_sectors; i++) { + uint32_t sector = area->subarea[s].first_sector + i; + uint32_t sector_size = flash_sector_size(sector, 1); + + if (offset == sector_offset) { + if (sectrue != erase_sector(sector)) { + return secfalse; + } + + *bytes_erased = sector_size; + return sectrue; + } + + sector_offset += sector_size; + } + } + + if (offset == sector_offset) { + return sectrue; + } + + return secfalse; +} diff --git a/storage/flash_area.h b/storage/flash_area.h new file mode 100644 index 00000000000..d88f2e8e54d --- /dev/null +++ b/storage/flash_area.h @@ -0,0 +1,92 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#ifndef FLASH_AREA_H +#define FLASH_AREA_H + +#include +#include "secbool.h" + +#include "flash.h" + +/** + * Flash driver interface is designed to abstract away differences between + * various MCUs used in Trezor devices. + * + * Generally, flash memory is divided into sectors. On different MCUs, sectors + * may have different sizes, and therefore, different number of sectors are used + * for a given purpose. For example, on STM32F4, the sectors are relatively + * large so we use single sector for Storage. On STM32U5, the sectors are + * smaller, so we use multiple sectors for the Storage. Storage implementation + * should not care about this, and should use flash_area_t interface to access + * the flash memory. + * + * flash_area_t represents a location in flash memory. It may be contiguous, or + * it may be composed of multiple non-contiguous subareas. + * + * flash_subarea_t represents a contiguous area in flash memory, specified by + * first_sector and num_sectors. + */ + +typedef struct { + uint16_t first_sector; + uint16_t num_sectors; +} flash_subarea_t; + +typedef struct { + flash_subarea_t subarea[4]; + uint8_t num_subareas; +} flash_area_t; + +uint32_t flash_area_get_size(const flash_area_t *area); + +uint16_t flash_area_total_sectors(const flash_area_t *area); + +const void *flash_area_get_address(const flash_area_t *area, uint32_t offset, + uint32_t size); + +#if defined FLASH_BIT_ACCESS +secbool __wur flash_area_write_byte(const flash_area_t *area, uint32_t offset, + uint8_t data); +secbool __wur flash_area_write_word(const flash_area_t *area, uint32_t offset, + uint32_t data); +#endif +secbool __wur flash_area_write_quadword(const flash_area_t *area, + uint32_t offset, const uint32_t *data); + +secbool __wur flash_area_write_burst(const flash_area_t *area, uint32_t offset, + const uint32_t *data); + +secbool __wur flash_area_write_block(const flash_area_t *area, uint32_t offset, + const flash_block_t block); + +secbool __wur flash_area_erase(const flash_area_t *area, + void (*progress)(int pos, int len)); +secbool __wur flash_area_erase_bulk(const flash_area_t *area, int count, + void (*progress)(int pos, int len)); + +// Erases the single sector in the designated flash area +// The 'offset' parameter must indicate the relative sector offset within the +// flash area If 'offset' is outside the bounds of the flash area, +// 'bytes_erased' is set to 0 otherwise, 'bytes_erased' is set to the size of +// the erased sector +secbool __wur flash_area_erase_partial(const flash_area_t *area, + uint32_t offset, uint32_t *bytes_erased); + +#endif // FLASH_AREA_H diff --git a/storage/flash_common.c b/storage/flash_common.c deleted file mode 100644 index 9b38c44d741..00000000000 --- a/storage/flash_common.c +++ /dev/null @@ -1,139 +0,0 @@ -#include "flash_common.h" - -#include "flash.h" - -secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data); - -secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data); - -const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size); - -static uint32_t flash_subarea_get_size(const flash_subarea_t *subarea) { - uint32_t size = 0; - for (int s = 0; s < subarea->num_sectors; s++) { - size += flash_sector_size(subarea->first_sector + s); - } - return size; -} - -static secbool subarea_get_sector_and_offset(const flash_subarea_t *subarea, - uint32_t offset, - uint16_t *sector_out, - uint32_t *offset_out) { - uint32_t tmp_offset = offset; - uint16_t sector = subarea->first_sector; - - // in correct subarea - for (int s = 0; s < subarea->num_sectors; s++) { - const uint32_t sector_size = flash_sector_size(sector); - if (tmp_offset < sector_size) { - *sector_out = sector; - *offset_out = tmp_offset; - return sectrue; - } - tmp_offset -= sector_size; - sector++; - } - return secfalse; -} - -uint32_t flash_area_get_size(const flash_area_t *area) { - uint32_t size = 0; - for (int i = 0; i < area->num_subareas; i++) { - size += flash_subarea_get_size(&area->subarea[i]); - } - return size; -} - -uint16_t flash_total_sectors(const flash_area_t *area) { - uint16_t total = 0; - for (int i = 0; i < area->num_subareas; i++) { - total += area->subarea[i].num_sectors; - } - return total; -} - -int32_t flash_get_sector_num(const flash_area_t *area, - uint32_t sector_inner_num) { - uint16_t sector = 0; - uint16_t remaining = sector_inner_num; - for (int i = 0; i < area->num_subareas; i++) { - if (remaining < area->subarea[i].num_sectors) { - sector = area->subarea[i].first_sector + remaining; - return sector; - } else { - remaining -= area->subarea[i].num_sectors; - } - } - - return -1; -} - -static secbool get_sector_and_offset(const flash_area_t *area, uint32_t offset, - uint16_t *sector_out, - uint32_t *offset_out) { - uint32_t tmp_offset = offset; - for (int i = 0; i < area->num_subareas; i++) { - uint32_t sub_size = flash_subarea_get_size(&area->subarea[i]); - if (tmp_offset >= sub_size) { - tmp_offset -= sub_size; - continue; - } - - return subarea_get_sector_and_offset(&area->subarea[i], tmp_offset, - sector_out, offset_out); - } - return secfalse; -} - -const void *flash_area_get_address(const flash_area_t *area, uint32_t offset, - uint32_t size) { - uint16_t sector; - uint32_t sector_offset; - - if (!get_sector_and_offset(area, offset, §or, §or_offset)) { - return NULL; - } - - return flash_get_address(sector, sector_offset, size); -} - -secbool flash_area_erase(const flash_area_t *area, - void (*progress)(int pos, int len)) { - return flash_area_erase_bulk(area, 1, progress); -} - -secbool flash_area_write_byte(const flash_area_t *area, uint32_t offset, - uint8_t data) { - uint16_t sector; - uint32_t sector_offset; - if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) { - return secfalse; - } - return flash_write_byte(sector, sector_offset, data); -} - -secbool flash_area_write_word(const flash_area_t *area, uint32_t offset, - uint32_t data) { - uint16_t sector; - uint32_t sector_offset; - if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) { - return secfalse; - } - return flash_write_word(sector, sector_offset, data); -} - -secbool flash_area_write_block(const flash_area_t *area, uint32_t offset, - const flash_block_t block) { - if (!FLASH_IS_ALIGNED(offset)) { - return secfalse; - } - - uint16_t sector; - uint32_t sector_offset; - if (sectrue != get_sector_and_offset(area, offset, §or, §or_offset)) { - return secfalse; - } - - return flash_write_block(sector, sector_offset, block); -} diff --git a/storage/flash_common.h b/storage/flash_common.h deleted file mode 100644 index 763882d2b22..00000000000 --- a/storage/flash_common.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef FLASH_COMMON_H -#define FLASH_COMMON_H - -#include -#include "secbool.h" - -typedef struct { - uint16_t first_sector; - uint16_t num_sectors; -} flash_subarea_t; - -typedef struct { - flash_subarea_t subarea[4]; - uint8_t num_subareas; -} flash_area_t; - -#define FLASH_BLOCK_SIZE (sizeof(uint32_t) * FLASH_BLOCK_WORDS) - -typedef uint32_t flash_block_t[FLASH_BLOCK_WORDS]; - -#if FLASH_BLOCK_WORDS == 1 -#define FLASH_ALIGN(X) (((X) + 3) & ~3) -#define FLASH_IS_ALIGNED(X) (((X)&3) == 0) -#elif FLASH_BLOCK_WORDS == 4 -#define FLASH_ALIGN(X) (((X) + 0xF) & ~0xF) -#define FLASH_IS_ALIGNED(X) (((X)&0xF) == 0) -#else -#error Unsupported number of FLASH_BLOCK_WORDS. -#endif - -void flash_init(void); - -secbool __wur flash_unlock_write(void); -secbool __wur flash_lock_write(void); - -uint32_t flash_sector_size(uint16_t sector); -uint16_t flash_total_sectors(const flash_area_t *area); -int32_t flash_get_sector_num(const flash_area_t *area, - uint32_t sector_inner_num); - -const void *flash_area_get_address(const flash_area_t *area, uint32_t offset, - uint32_t size); -uint32_t flash_area_get_size(const flash_area_t *area); - -secbool __wur flash_area_erase(const flash_area_t *area, - void (*progress)(int pos, int len)); -secbool __wur flash_area_erase_bulk(const flash_area_t *area, int count, - void (*progress)(int pos, int len)); - -#if defined FLASH_BIT_ACCESS -secbool __wur flash_area_write_byte(const flash_area_t *area, uint32_t offset, - uint8_t data); -secbool __wur flash_area_write_word(const flash_area_t *area, uint32_t offset, - uint32_t data); -#endif -secbool __wur flash_area_write_block(const flash_area_t *area, uint32_t offset, - const flash_block_t block); - -secbool flash_write_block(uint16_t sector, uint32_t offset, - const flash_block_t block); - -#endif diff --git a/storage/flash_ll.h b/storage/flash_ll.h new file mode 100644 index 00000000000..c7704cf0d20 --- /dev/null +++ b/storage/flash_ll.h @@ -0,0 +1,93 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * 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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that 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 . + */ + +#ifndef FLASH_LL_H_ +#define FLASH_LL_H_ + +#include +#include + +// Flash memory low-level API, providing abstraction for +// various flash archictures found on STM32 MCUs + +// The 'sector' parameter in this API can represent +// 1. Non-uniform sector number on STM32F4 +// 2. Uniform page number on STM32U5 + +#define FLASH_BLOCK_SIZE (sizeof(uint32_t) * FLASH_BLOCK_WORDS) + +typedef uint32_t flash_block_t[FLASH_BLOCK_WORDS]; + +#if FLASH_BLOCK_WORDS == 1 +#define FLASH_ALIGN(X) (((X) + 3) & ~3) +#define FLASH_IS_ALIGNED(X) (((X)&3) == 0) +#elif FLASH_BLOCK_WORDS == 4 +#define FLASH_ALIGN(X) (((X) + 0xF) & ~0xF) +#define FLASH_IS_ALIGNED(X) (((X)&0xF) == 0) +#else +#error Unsupported number of FLASH_BLOCK_WORDS. +#endif + +// Returns the size of the a continuous area of sectors +// Returns 0 if any of the sectors is out of range +uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count); + +// Returns number of the sector/page at specified byte 'offset' +// from the beginning of the 'first_sector' +uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset); + +// Returns the physical address of a byte on specified 'offset' in the specified +// 'sector'. Checks if it's possible to access continues space of 'size' bytes +// Returns NULL i [offset, offset + size] is of out of the specified sector +const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size); + +// Unlocks the flash memory for writes/erase operations +// Flash must be locked again as soon as possible +secbool __wur flash_unlock_write(void); + +// Locks the flash memory for writes/erase operations +secbool __wur flash_lock_write(void); + +#if defined FLASH_BIT_ACCESS + +// Writes a single byte to the specified 'offset' inside a flash 'sector' +secbool __wur flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data); + +// Writes a single 32-bit word to the specified 'offset' inside a flash 'sector' +secbool __wur flash_write_word(uint16_t sector, uint32_t offset, uint32_t data); + +#endif + +// Writes a 16-byte block to specified 'offset' inside a flash 'sector' +secbool __wur flash_write_quadword(uint16_t sector, uint32_t offset, + const uint32_t *data); + +// Writes a 128-byte burst to specified 'offset' inside a flash 'sector' +secbool __wur flash_write_burst(uint16_t sector, uint32_t offset, + const uint32_t *data); + +// Erases a single sector/page of flash memory +secbool __wur flash_sector_erase(uint16_t sector); + +// Writes a block to specified 'offset' inside a flash 'sector' +// Block represents a natural unit of the given flash memory +secbool flash_write_block(uint16_t sector, uint32_t offset, + const flash_block_t block); + +#endif // FLASH_LL_H diff --git a/storage/norcow.c b/storage/norcow.c index 70f20185f9e..06505bfd626 100644 --- a/storage/norcow.c +++ b/storage/norcow.c @@ -20,7 +20,7 @@ #include #include "common.h" -#include "flash.h" +#include "flash_area.h" #include "memzero.h" #include "norcow.h" #include "storage_utils.h" diff --git a/storage/norcow_bitwise.h b/storage/norcow_bitwise.h index 029f66a567a..9171762b874 100644 --- a/storage/norcow_bitwise.h +++ b/storage/norcow_bitwise.h @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -#include "flash_common.h" +#include "flash_area.h" #define COUNTER_TAIL_WORDS 2 #define NORCOW_MAX_PREFIX_LEN (NORCOW_KEY_LEN + NORCOW_LEN_LEN) diff --git a/storage/norcow_blockwise.h b/storage/norcow_blockwise.h index 3de1092b39f..9168f6dcb0d 100644 --- a/storage/norcow_blockwise.h +++ b/storage/norcow_blockwise.h @@ -18,7 +18,7 @@ */ #include -#include "flash_common.h" +#include "flash_area.h" #define COUNTER_TAIL_WORDS 0 // Small items are encoded more efficiently. diff --git a/storage/tests/c/Makefile b/storage/tests/c/Makefile index 099b84d0412..eef7c87e464 100644 --- a/storage/tests/c/Makefile +++ b/storage/tests/c/Makefile @@ -14,7 +14,7 @@ SRC = storage/tests/c/flash.c SRC += storage/tests/c/common.c SRC += storage/tests/c/random_delays.c SRC += storage/tests/c/test_layout.c -SRC += storage/flash_common.c +SRC += storage/flash_area.c SRC += storage/storage.c SRC += storage/storage_utils.c SRC += storage/norcow.c diff --git a/storage/tests/c/flash.c b/storage/tests/c/flash.c index 2914fd5ce15..2098838d98c 100644 --- a/storage/tests/c/flash.c +++ b/storage/tests/c/flash.c @@ -63,11 +63,29 @@ secbool flash_unlock_write(void) { return sectrue; } secbool flash_lock_write(void) { return sectrue; } -uint32_t flash_sector_size(uint16_t sector) { - if (sector >= FLASH_SECTOR_COUNT) { +uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count) { + if (first_sector + sector_count >= FLASH_SECTOR_COUNT) { return 0; } - return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + return FLASH_SECTOR_TABLE[first_sector + sector_count] - + FLASH_SECTOR_TABLE[first_sector]; +} + +uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset) { + uint16_t sector = first_sector; + + while (sector < FLASH_SECTOR_COUNT) { + uint32_t sector_size = + FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + + if (offset < sector_size) { + break; + } + offset -= sector_size; + sector++; + } + + return sector; } const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) { @@ -82,69 +100,58 @@ const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size) { return FLASH_BUFFER + addr - FLASH_SECTOR_TABLE[0]; } -secbool flash_area_erase_bulk(const flash_area_t *area, int count, - void (*progress)(int pos, int len)) { - ensure(flash_unlock_write(), NULL); +secbool flash_sector_erase(uint16_t sector) { + if (sector >= FLASH_SECTOR_COUNT) { + return secfalse; + } + const uint32_t offset = FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0]; + const uint32_t size = + FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; + memset(FLASH_BUFFER + offset, 0xFF, size); + return sectrue; +} - int total_sectors = 0; - int done_sectors = 0; - for (int a = 0; a < count; a++) { - for (int i = 0; i < area[a].num_subareas; i++) { - total_sectors += area[a].subarea[i].num_sectors; - } +static secbool flash_write(uint16_t sector, uint32_t offset, + const uint8_t *data, size_t data_size) { + // check proper alignment + if ((offset % data_size) != 0) { + return secfalse; } - if (progress) { - progress(0, total_sectors); + uint8_t *flash = (uint8_t *)flash_get_address(sector, offset, data_size); + + if (flash == NULL) { + return secfalse; } - for (int a = 0; a < count; a++) { - for (int s = 0; s < area[a].num_subareas; s++) { - for (int i = 0; i < area[a].subarea[s].num_sectors; i++) { - int sector = area[a].subarea[s].first_sector + i; - - const uint32_t offset = - FLASH_SECTOR_TABLE[sector] - FLASH_SECTOR_TABLE[0]; - const uint32_t size = - FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; - memset(FLASH_BUFFER + offset, 0xFF, size); - - done_sectors++; - if (progress) { - progress(done_sectors, total_sectors); - } - } + // check if not writing ones to zeroes + for (size_t i = 0; i < data_size; i++) { + if (data[i] != (data[i] & flash[i])) { + return secfalse; } } - ensure(flash_lock_write(), NULL); + + memcpy(flash, data, data_size); + return sectrue; } secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data) { - uint8_t *flash = (uint8_t *)flash_get_address(sector, offset, 1); - if (!flash) { - return secfalse; - } - if ((flash[0] & data) != data) { - return secfalse; // we cannot change zeroes to ones - } - flash[0] = data; - return sectrue; + return flash_write(sector, offset, (uint8_t *)&data, sizeof(uint8_t)); } secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data) { - if (offset % 4) { // we write only at 4-byte boundary - return secfalse; - } - uint32_t *flash = (uint32_t *)flash_get_address(sector, offset, sizeof(data)); - if (!flash) { - return secfalse; - } - if ((flash[0] & data) != data) { - return secfalse; // we cannot change zeroes to ones - } - flash[0] = data; - return sectrue; + return flash_write(sector, offset, (uint8_t *)&data, sizeof(uint32_t)); +} + +secbool flash_write_quadword(uint16_t sector, uint32_t offset, + const uint32_t *data) { + return flash_write(sector, offset, (uint8_t *)data, 4 * sizeof(uint32_t)); +} + +secbool flash_write_burst(uint16_t sector, uint32_t offset, + const uint32_t *data) { + return flash_write(sector, offset, (uint8_t *)data, 32 * sizeof(uint32_t)); } secbool flash_write_block(uint16_t sector, uint32_t offset, diff --git a/storage/tests/c/flash.h b/storage/tests/c/flash.h index 11821beb039..65aa2123a86 100644 --- a/storage/tests/c/flash.h +++ b/storage/tests/c/flash.h @@ -22,15 +22,7 @@ #include #include +#include "flash_ll.h" #include "secbool.h" -#include "flash_common.h" -#include "test_layout.h" - -uint32_t flash_sector_size(uint16_t sector); - -secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data); - -secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data); - #endif diff --git a/storage/tests/c/norcow_config.h b/storage/tests/c/norcow_config.h index b2af9d93454..3aa99a827a7 100644 --- a/storage/tests/c/norcow_config.h +++ b/storage/tests/c/norcow_config.h @@ -21,6 +21,7 @@ #define __NORCOW_CONFIG_H__ #include "flash.h" +#include "test_layout.h" #define NORCOW_SECTOR_COUNT 2 #define NORCOW_SECTOR_SIZE (64 * 1024) diff --git a/storage/tests/c/test_layout.h b/storage/tests/c/test_layout.h index 1223f198fc4..62e7cd25eed 100644 --- a/storage/tests/c/test_layout.h +++ b/storage/tests/c/test_layout.h @@ -3,7 +3,7 @@ #define STORAGE_AREAS_COUNT 2 -#include "flash_common.h" +#include "flash_area.h" extern const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT]; diff --git a/vendor/cmsis_5 b/vendor/cmsis_5 new file mode 160000 index 00000000000..a75f01746df --- /dev/null +++ b/vendor/cmsis_5 @@ -0,0 +1 @@ +Subproject commit a75f01746df18bb5b929dfb8dc6c9407fac3a0f3 diff --git a/vendor/cmsis_device_u5 b/vendor/cmsis_device_u5 new file mode 160000 index 00000000000..f439f968725 --- /dev/null +++ b/vendor/cmsis_device_u5 @@ -0,0 +1 @@ +Subproject commit f439f9687257f8e69daccb8dc6c4d1ed8dab73aa diff --git a/vendor/stm32u5xx_hal_driver b/vendor/stm32u5xx_hal_driver new file mode 160000 index 00000000000..270974ea816 --- /dev/null +++ b/vendor/stm32u5xx_hal_driver @@ -0,0 +1 @@ +Subproject commit 270974ea816779656ac8bb183344ac017e693677