From 472a8bebd295bdb079eeb3b8f5d4df2c4a728b65 Mon Sep 17 00:00:00 2001 From: cepetr Date: Sun, 17 Mar 2024 13:01:59 +0100 Subject: [PATCH] WIP - drawlib - low level refactoring --- core/Makefile | 20 +- core/SConscript.bootloader | 12 +- core/SConscript.firmware | 34 +- core/SConscript.unix | 62 +- .../extmod/modtrezorui/modtrezorui-display.h | 2 + core/embed/gdc/gdc_bitmap.h | 106 -- core/embed/gdc/gdc_clip.h | 92 - core/embed/gdc/gdc_core.c | 185 -- core/embed/gdc/gdc_core.h | 107 -- core/embed/gdc/gdc_geom.h | 88 - core/embed/gdc/gdc_rgb565.c | 74 - core/embed/gdc/gdc_rgba8888.c | 58 - core/embed/gdc/gdc_text.c | 174 -- core/embed/gdc/gdc_wnd565.c | 79 - core/embed/gdc/gdc_wnd565.h | 70 - core/embed/gdc/gdc_wnd565_ops.c | 57 - core/embed/lib/display_draw.c | 4 +- .../embed/{gdc/gdc_color.c => lib/gl_color.c} | 30 +- .../embed/{gdc/gdc_color.h => lib/gl_color.h} | 101 +- core/embed/{gdc/gdc_ops.h => lib/gl_dma2d.h} | 34 +- .../gdc_mono8_ops.c => lib/gl_dma2d_mono8.c} | 17 +- .../gl_dma2d_rgb565.c} | 16 +- core/embed/lib/gl_draw.c | 226 +++ core/embed/lib/gl_draw.h | 135 ++ core/embed/lib/terminal.c | 4 + core/embed/rust/Cargo.toml | 4 + core/embed/rust/build.rs | 15 +- core/embed/rust/src/trezorhal/display.rs | 10 +- core/embed/rust/src/trezorhal/dma2d_new.rs | 15 +- .../rust/src/ui/shape/display/fake_display.rs | 12 + .../rust/src/ui/shape/display/fb_mono8.rs | 45 + .../rust/src/ui/shape/display/fb_rgb565.rs | 51 + .../rust/src/ui/shape/display/fb_rgba8888.rs | 51 + .../src/ui/shape/{model => display}/memory.md | 0 core/embed/rust/src/ui/shape/display/mod.rs | 24 + .../model_tt.rs => display/nofb_rgb565.rs} | 14 +- core/embed/rust/src/ui/shape/mod.rs | 4 +- core/embed/rust/src/ui/shape/model/mod.rs | 9 - .../embed/rust/src/ui/shape/model/model_tr.rs | 57 - core/embed/rust/trezorhal.h | 3 +- .../embed/trezorhal/boards/stm32f429i-disc1.h | 6 +- core/embed/trezorhal/boards/stm32u5a9j-dk.h | 5 +- core/embed/trezorhal/boards/trezor_1.h | 3 +- core/embed/trezorhal/boards/trezor_r_v10.h | 4 +- core/embed/trezorhal/boards/trezor_r_v3.h | 4 +- core/embed/trezorhal/boards/trezor_r_v4.h | 4 +- core/embed/trezorhal/boards/trezor_r_v6.h | 4 +- core/embed/trezorhal/boards/trezor_t.h | 11 +- .../embed/trezorhal/boards/trezor_t3t1_revE.h | 14 +- core/embed/trezorhal/boards/trezor_t3t1_v4.h | 14 +- core/embed/trezorhal/display.h | 9 + core/embed/trezorhal/dma2d.h | 6 +- core/embed/trezorhal/stm32f4/common.c | 4 + .../stm32f4/display/st-7789/display_driver.c | 194 ++ .../stm32f4/display/st-7789/display_fb.c | 160 ++ .../stm32f4/display/st-7789/display_fb.h | 46 + .../stm32f4/display/st-7789/display_io.c | 145 ++ .../stm32f4/display/st-7789/display_io.h | 67 + .../stm32f4/display/st-7789/display_panel.c | 235 +++ .../stm32f4/display/st-7789/display_panel.h | 52 + .../stm32f4/display/st-7789/panels/154a.c | 132 ++ .../stm32f4/display/st-7789/panels/154a.h} | 15 +- .../display/st-7789/panels/lx154a2411.c | 82 + .../display/st-7789/panels/lx154a2411.h | 27 + .../display/st-7789/panels/lx154a2422.c | 150 ++ .../display/st-7789/panels/lx154a2422.h} | 33 +- .../stm32f4/display/st-7789/panels/tf15411a.c | 165 ++ .../stm32f4/display/st-7789/panels/tf15411a.h | 28 + .../display/stm32f429i-disc1/display_driver.c | 121 ++ .../stm32f429i-disc1/display_internal.h} | 39 +- .../display/stm32f429i-disc1/display_ltdc.c | 291 +++ .../display/stm32f429i-disc1/ili9341_spi.c | 512 ++++++ .../display/stm32f429i-disc1/ili9341_spi.h | 13 + .../stm32f4/display/ug-2828/display_driver.c | 393 +++++ .../stm32f4/display/vg-2864/display_driver.c | 351 ++++ core/embed/trezorhal/stm32f4/displays/ltdc.c | 18 +- core/embed/trezorhal/stm32f4/displays/ltdc.h | 4 +- .../trezorhal/stm32f4/displays/st7789v.c | 6 +- .../stm32f4/{dma2d_gdc.c => dma2d_gl.c} | 59 +- core/embed/trezorhal/stm32f4/touch/ft6x36.c | 4 +- core/embed/trezorhal/stm32u5/display/st-7789 | 1 + .../display/stm32u5a9j-dk/display_driver.c | 135 ++ .../display/stm32u5a9j-dk/display_fb.c | 60 + .../stm32u5a9j-dk/display_gfxmmu_lut.h | 1006 +++++++++++ .../display/stm32u5a9j-dk/display_internal.h | 55 + .../display/stm32u5a9j-dk/display_ltdc_dsi.c | 1562 +++++++++++++++++ core/embed/trezorhal/stm32u5/display/vg-2864 | 1 + core/embed/trezorhal/stm32u5/displays/dsi.h | 4 - core/embed/trezorhal/stm32u5/dma2d_gl.c | 1 + core/embed/trezorhal/unix/display_driver.c | 409 +++++ core/embed/trezorhal/xdisplay.h | 135 ++ core/embed/trezorhal/xdisplay_legacy.c | 50 + core/embed/trezorhal/xdisplay_legacy.h | 34 + core/site_scons/boards/discovery.py | 26 +- core/site_scons/boards/discovery2.py | 26 +- core/site_scons/boards/trezor_r_v10.py | 17 +- core/site_scons/boards/trezor_r_v3.py | 17 +- core/site_scons/boards/trezor_r_v4.py | 17 +- core/site_scons/boards/trezor_r_v6.py | 17 +- core/site_scons/boards/trezor_t.py | 52 +- core/site_scons/boards/trezor_t3t1_revE.py | 28 +- core/site_scons/boards/trezor_t3t1_v4.py | 28 +- 102 files changed, 7734 insertions(+), 1478 deletions(-) delete mode 100644 core/embed/gdc/gdc_bitmap.h delete mode 100644 core/embed/gdc/gdc_clip.h delete mode 100644 core/embed/gdc/gdc_core.c delete mode 100644 core/embed/gdc/gdc_core.h delete mode 100644 core/embed/gdc/gdc_geom.h delete mode 100644 core/embed/gdc/gdc_rgb565.c delete mode 100644 core/embed/gdc/gdc_rgba8888.c delete mode 100644 core/embed/gdc/gdc_text.c delete mode 100644 core/embed/gdc/gdc_wnd565.c delete mode 100644 core/embed/gdc/gdc_wnd565.h delete mode 100644 core/embed/gdc/gdc_wnd565_ops.c rename core/embed/{gdc/gdc_color.c => lib/gl_color.c} (52%) rename core/embed/{gdc/gdc_color.h => lib/gl_color.h} (72%) rename core/embed/{gdc/gdc_ops.h => lib/gl_dma2d.h} (70%) rename core/embed/{gdc/gdc_mono8_ops.c => lib/gl_dma2d_mono8.c} (90%) rename core/embed/{gdc/gdc_rgb565_ops.c => lib/gl_dma2d_rgb565.c} (91%) create mode 100644 core/embed/lib/gl_draw.c create mode 100644 core/embed/lib/gl_draw.h create mode 100644 core/embed/rust/src/ui/shape/display/fake_display.rs create mode 100644 core/embed/rust/src/ui/shape/display/fb_mono8.rs create mode 100644 core/embed/rust/src/ui/shape/display/fb_rgb565.rs create mode 100644 core/embed/rust/src/ui/shape/display/fb_rgba8888.rs rename core/embed/rust/src/ui/shape/{model => display}/memory.md (100%) create mode 100644 core/embed/rust/src/ui/shape/display/mod.rs rename core/embed/rust/src/ui/shape/{model/model_tt.rs => display/nofb_rgb565.rs} (88%) delete mode 100644 core/embed/rust/src/ui/shape/model/mod.rs delete mode 100644 core/embed/rust/src/ui/shape/model/model_tr.rs create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/display_driver.c create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/display_fb.c create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/display_fb.h create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/display_io.c create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/display_io.h create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/display_panel.c create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/display_panel.h create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.c rename core/embed/{gdc/gdc.h => trezorhal/stm32f4/display/st-7789/panels/154a.h} (80%) create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.h create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c rename core/embed/{gdc/gdc_text.h => trezorhal/stm32f4/display/st-7789/panels/lx154a2422.h} (53%) create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c create mode 100644 core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.h create mode 100644 core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c rename core/embed/{gdc/gdc_dma2d.h => trezorhal/stm32f4/display/stm32f429i-disc1/display_internal.h} (55%) create mode 100644 core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c create mode 100644 core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c create mode 100644 core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.h create mode 100644 core/embed/trezorhal/stm32f4/display/ug-2828/display_driver.c create mode 100644 core/embed/trezorhal/stm32f4/display/vg-2864/display_driver.c rename core/embed/trezorhal/stm32f4/{dma2d_gdc.c => dma2d_gl.c} (81%) create mode 120000 core/embed/trezorhal/stm32u5/display/st-7789 create mode 100644 core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c create mode 100644 core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c create mode 100644 core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_gfxmmu_lut.h create mode 100644 core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_internal.h create mode 100644 core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c create mode 120000 core/embed/trezorhal/stm32u5/display/vg-2864 create mode 120000 core/embed/trezorhal/stm32u5/dma2d_gl.c create mode 100644 core/embed/trezorhal/unix/display_driver.c create mode 100644 core/embed/trezorhal/xdisplay.h create mode 100644 core/embed/trezorhal/xdisplay_legacy.c create mode 100644 core/embed/trezorhal/xdisplay_legacy.h diff --git a/core/Makefile b/core/Makefile index dba27525e..ae74b037f 100644 --- a/core/Makefile +++ b/core/Makefile @@ -233,18 +233,20 @@ build_embed: build_boardloader build_bootloader build_firmware # build boardload build_boardloader: ## build boardloader $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ - CMAKELISTS="$(CMAKELISTS)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin + CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin build_bootloader: ## build bootloader $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ - CMAKELISTS="$(CMAKELISTS)" BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin + CMAKELISTS="$(CMAKELISTS)" BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" \ + NEW_RENDERING="$(NEW_RENDERING)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin build_bootloader_ci: ## build CI device testing bootloader $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_CI_BUILD_DIR)/bootloader.bin build_bootloader_emu: ## build the unix bootloader emulator - $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf + $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ + CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf build_prodtest: ## build production test firmware $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ @@ -252,7 +254,7 @@ build_prodtest: ## build production test firmware build_reflash: ## build reflash firmware + reflash image $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ - CMAKELISTS="$(CMAKELISTS)" $(REFLASH_BUILD_DIR)/reflash.bin + CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(REFLASH_BUILD_DIR)/reflash.bin dd if=build/boardloader/boardloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=0 dd if=build/bootloader/bootloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=49152 @@ -261,24 +263,26 @@ build_firmware: templates build_cross ## build firmware with frozen modules TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" \ BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" \ - DISABLE_OPTIGA="$(DISABLE_OPTIGA)" \ + DISABLE_OPTIGA="$(DISABLE_OPTIGA)" NEW_RENDERING="$(NEW_RENDERING)"\ $(FIRMWARE_BUILD_DIR)/firmware.bin build_unix: templates ## build unix port $(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \ TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ - PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" + PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \ + NEW_RENDERING="$(NEW_RENDERING)" build_unix_frozen: templates build_cross ## build unix port with frozen modules $(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \ TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \ - TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1 + TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1 NEW_RENDERING="$(NEW_RENDERING)" build_unix_debug: templates ## build unix port $(SCONS) --max-drift=1 CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \ TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ - BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1 + BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1 \ + NEW_RENDERING="$(NEW_RENDERING)" build_cross: ## build mpy-cross port $(MAKE) -C vendor/micropython/mpy-cross $(CROSS_PORT_OPTS) diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index a40309ce3..48d4d65a3 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -81,21 +81,15 @@ CPPPATH_MOD += [ SOURCE_MOD += [ 'embed/extmod/modtrezorcrypto/rand.c', - 'embed/gdc/gdc_color.c', - 'embed/gdc/gdc_core.c', - 'embed/gdc/gdc_mono8_ops.c', - 'embed/gdc/gdc_rgb565.c', - 'embed/gdc/gdc_rgb565_ops.c', - 'embed/gdc/gdc_rgba8888.c', - 'embed/gdc/gdc_text.c', - 'embed/gdc/gdc_wnd565.c', - 'embed/gdc/gdc_wnd565_ops.c', 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display_draw.c', 'embed/lib/display_utils.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gl_color.c', + 'embed/lib/gl_dma2d_mono8.c', + 'embed/lib/gl_dma2d_rgb565.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 08545e565..989003400 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -13,6 +13,7 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) PYOPT = ARGUMENTS.get('PYOPT', '1') DISABLE_OPTIGA = ARGUMENTS.get('DISABLE_OPTIGA', '0') == '1' +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' FEATURE_FLAGS = { @@ -24,6 +25,8 @@ FEATURE_FLAGS = { FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"] if DISABLE_OPTIGA and PYOPT == '0': FEATURES_WANTED.remove("optiga") +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") CCFLAGS_MOD = '' CPPPATH_MOD = [] @@ -188,21 +191,14 @@ CPPPATH_MOD += [ ] SOURCE_MOD += [ 'embed/extmod/modtrezorui/modtrezorui.c', - 'embed/gdc/gdc_color.c', - 'embed/gdc/gdc_core.c', - 'embed/gdc/gdc_mono8_ops.c', - 'embed/gdc/gdc_rgb565.c', - 'embed/gdc/gdc_rgb565_ops.c', - 'embed/gdc/gdc_rgba8888.c', - 'embed/gdc/gdc_text.c', - 'embed/gdc/gdc_wnd565.c', - 'embed/gdc/gdc_wnd565_ops.c', 'embed/lib/buffers.c', 'embed/lib/colors.c', - 'embed/lib/display_draw.c', 'embed/lib/display_utils.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gl_color.c', + 'embed/lib/gl_dma2d_rgb565.c', + 'embed/lib/gl_dma2d_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', @@ -213,6 +209,17 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/tinflate.c', ] +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + SOURCE_MOD += [ + 'embed/lib/gl_draw.c', + ] +else: + SOURCE_MOD += [ + 'embed/lib/display_draw.c', + ] + + CPPDEFINES_MOD += [ 'TREZOR_UI2', 'TRANSLATIONS', @@ -741,11 +748,14 @@ def cargo_build(): features.append('universal_fw') features.append('ui') features.append('translations') - features.append('new_rendering') + + if NEW_RENDERING: + features.append('new_rendering') + if PYOPT == '0': features.append('debug') features.append('ui_debug') - if TREZOR_MODEL in ('T',): + if TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'): features.append('ui_antialiasing') features.append('ui_blurring') features.append('ui_jpeg_decoder') diff --git a/core/SConscript.unix b/core/SConscript.unix index 448f3a78d..59ba08c8c 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -10,6 +10,7 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') DMA2D = TREZOR_MODEL in ('T', 'T3T1') OPTIGA = TREZOR_MODEL in ('R', 'T3T1') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' if TREZOR_MODEL in ('DISC1', 'DISC2'): # skip unix build @@ -190,21 +191,14 @@ CPPPATH_MOD += [ ] SOURCE_MOD += [ 'embed/extmod/modtrezorui/modtrezorui.c', - 'embed/gdc/gdc_color.c', - 'embed/gdc/gdc_core.c', - 'embed/gdc/gdc_mono8_ops.c', - 'embed/gdc/gdc_rgb565.c', - 'embed/gdc/gdc_rgb565_ops.c', - 'embed/gdc/gdc_rgba8888.c', - 'embed/gdc/gdc_text.c', - 'embed/gdc/gdc_wnd565.c', - 'embed/gdc/gdc_wnd565_ops.c', 'embed/lib/buffers.c', 'embed/lib/colors.c', - 'embed/lib/display_draw.c', 'embed/lib/display_utils.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gl_color.c', + 'embed/lib/gl_dma2d_rgb565.c', + 'embed/lib/gl_dma2d_mono8.c', 'embed/lib/image.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', @@ -214,6 +208,16 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/tinflate.c', ] +if NEW_RENDERING: + SOURCE_MOD += [ + 'embed/lib/gl_draw.c', + ] +else: + SOURCE_MOD += [ + 'embed/lib/display_draw.c', + ] + + if TREZOR_MODEL in ('1', ): SOURCE_MOD += [ 'embed/models/model_T1B1_layout.c', @@ -247,6 +251,17 @@ if FROZEN: if RASPI: CPPDEFINES_MOD += ['TREZOR_EMULATOR_RASPI'] +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + if TREZOR_MODEL in ('T',): + CPPDEFINES_MOD += ['DISPLAY_RGB565'] + elif TREZOR_MODEL in ('R', '1',): + CPPDEFINES_MOD += ['XFRAMEBUFFER', 'DISPLAY_MONO'] + elif TREZOR_MODEL in ('T3T1',): + CPPDEFINES_MOD += ['XFRAMEBUFFER', 'DISPLAY_RGB565'] + + + # modtrezorutils SOURCE_MOD += [ 'embed/extmod/modtrezorutils/modtrezorutils.c', @@ -391,7 +406,6 @@ SOURCE_MICROPYTHON = [ SOURCE_UNIX = [ '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', @@ -407,6 +421,18 @@ SOURCE_UNIX = [ 'vendor/micropython/ports/unix/input.c', 'vendor/micropython/ports/unix/unix_mphal.c', ] + +if NEW_RENDERING: + SOURCE_MOD += [ + 'embed/trezorhal/unix/display_driver.c', + 'embed/trezorhal/xdisplay_legacy.c', + ] +else: + SOURCE_MOD += [ + 'embed/trezorhal/unix/display-unix.c', + ] + + if TREZOR_MODEL in ('T', 'R', 'T3T1'): SOURCE_UNIX += [ 'embed/trezorhal/unix/sbu.c', @@ -421,6 +447,7 @@ if DMA2D: CPPDEFINES_MOD += [ 'USE_DMA2D', ] + SOURCE_UNIX += [ 'embed/lib/dma2d_emul.c', ] @@ -830,7 +857,6 @@ def cargo_build(): features.append('universal_fw') features.append('ui') features.append('translations') - features.append('new_rendering') if PYOPT == '0': features.append('debug') if DMA2D: @@ -845,6 +871,18 @@ def cargo_build(): if TREZOR_MODEL in ('R', '1'): features.append('button') + + if NEW_RENDERING: + features.append('new_rendering') + if TREZOR_MODEL in ('T',): + features.append('display_rgb565') + elif TREZOR_MODEL in ('R', '1',): + features.append('display_mono') + features.append('xframebuffer') + elif TREZOR_MODEL in ('T3T1',): + features.append('display_rgb565') + features.append('xframebuffer') + env.get('ENV')['TREZOR_MODEL'] = TREZOR_MODEL return f'cd embed/rust; cargo build --profile {RUST_PROFILE} --target-dir=../../build/unix/rust --no-default-features --features "{" ".join(features)}" --target {TARGET}' diff --git a/core/embed/extmod/modtrezorui/modtrezorui-display.h b/core/embed/extmod/modtrezorui/modtrezorui-display.h index 85662585a..c06a4d2f3 100644 --- a/core/embed/extmod/modtrezorui/modtrezorui-display.h +++ b/core/embed/extmod/modtrezorui/modtrezorui-display.h @@ -18,6 +18,8 @@ */ #include "display.h" +#include "display_draw.h" +#include "fonts/fonts.h" /// class Display: /// """ diff --git a/core/embed/gdc/gdc_bitmap.h b/core/embed/gdc/gdc_bitmap.h deleted file mode 100644 index 842f32011..000000000 --- a/core/embed/gdc/gdc_bitmap.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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 GDC_BITMAP_H -#define GDC_BITMAP_H - -#include "gdc_color.h" -#include "gdc_geom.h" - -#include -#include - -// forward declaration -typedef struct gdc_vmt gdc_vmt_t; - -// ------------------------------------------------------------------------ -// GDC Bitmap pixel format -// - -typedef enum { - GDC_FORMAT_UNKNOWN, // - GDC_FORMAT_MONO1, // 1-bpp per pixel - GDC_FORMAT_MONO4, // 4-bpp per pixel - GDC_FORMAT_RGB565, // 16-bpp per pixel - GDC_FORMAT_RGBA8888, // 32-bpp - -} gdc_format_t; - -// ------------------------------------------------------------------------ -// GDC Bitmap Attributes -// - -#define GDC_BITMAP_READ_ONLY 0x01 // Read-only data -// #define GDC_BITMAP_DMA_READ 0x02 // DMA read pending -// #define GDC_BITMAP_DMA_WRITE 0x04 // DMA write pending - -// ------------------------------------------------------------------------ -// GDC Bitmap -// -// Structure holding pointer to the bitmap data, its format and sizes -// -// Note: gdc_bitmap_t itself can be used as GDC as long as it contains -// valid gdc virtual table pointer. - -typedef struct gdc_bitmap { - // GDC virtual method table - // (must be the first field of the structure) - const gdc_vmt_t* vmt; - // pointer to top-left pixel - void* ptr; - // stride in bytes - size_t stride; - // size in pixels - gdc_size_t size; - // format of pixels, GDC_FORMAT_xxx - uint8_t format; - // attributes, GDC_BITMAP_xxx - uint8_t attrs; - -} gdc_bitmap_t; - -// Initializes RGB565 bitmap structure -// GDC and format fields and filled automatically. -gdc_bitmap_t gdc_bitmap_rgb565(void* data_ptr, size_t stride, gdc_size_t size, - uint8_t attrs); - -// Initializes RGBA8888 bitmap structure -// GDC and format fields and filled automatically. -gdc_bitmap_t gdc_bitmap_rgba8888(void* data_ptr, size_t stride, gdc_size_t size, - uint8_t attrs); - -// ------------------------------------------------------------------------ -// GDC Bitmap reference -// -// Structure is used when bitmap is beeing drawed to supply -// additional parameters - -typedef struct { - // soruce bitmap - const gdc_bitmap_t* bitmap; - // offset used when bitmap is drawed on gdc - gdc_offset_t offset; - // foreground color (used with MONOx formats) - gdc_color_t fg_color; - // background color (used with MONOx formats) - gdc_color_t bg_color; - -} gdc_bitmap_ref_t; - -#endif // GDC_BITMAP_H diff --git a/core/embed/gdc/gdc_clip.h b/core/embed/gdc/gdc_clip.h deleted file mode 100644 index daa250bed..000000000 --- a/core/embed/gdc/gdc_clip.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 GDC_CLIP_H -#define GDC_CLIP_H - -#include -#include "gdc.h" - -typedef struct { - int16_t dst_x; - int16_t dst_y; - int16_t src_x; - int16_t src_y; - int16_t width; - int16_t height; -} gdc_clip_t; - -static inline gdc_clip_t gdc_clip(gdc_rect_t dst, gdc_size_t size, - const gdc_bitmap_ref_t* src) { - int16_t dst_x = dst.x0; - int16_t dst_y = dst.y0; - - int16_t src_x = 0; - int16_t src_y = 0; - - if (src != NULL) { - src_x += src->offset.x; - src_y += src->offset.y; - - // Normalize negative x-offset of src bitmap - if (src_x < 0) { - dst_x -= src_x; - src_x = 0; - } - - // Normalize negative y-offset of src bitmap - if (src_y < 0) { - dst_y -= src_y; - src_y = 0; - } - } - - // Normalize negative top-left of destination rectangle - if (dst_x < 0) { - src_x -= dst_x; - dst_x = 0; - } - - if (dst_y < 0) { - src_y -= dst_y; - dst_y = 0; - } - - // Calculate dimension of effective rectangle - int16_t width = MIN(size.x, dst.x1) - dst_x; - int16_t height = MIN(size.y, dst.y1) - dst_y; - - if (src != NULL) { - width = MIN(width, src->bitmap->size.x - src_x); - height = MIN(height, src->bitmap->size.y - src_y); - } - - gdc_clip_t clip = { - .dst_x = dst_x, - .dst_y = dst_y, - .src_x = src_x, - .src_y = src_y, - .width = width, - .height = height, - }; - - return clip; -} - -#endif // GDC_CLIP_H diff --git a/core/embed/gdc/gdc_core.c b/core/embed/gdc/gdc_core.c deleted file mode 100644 index 4eabecf9a..000000000 --- a/core/embed/gdc/gdc_core.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * 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 "gdc_core.h" -#include "gdc_clip.h" - -#include "dma2d.h" - -void gdc_release(gdc_t* gdc) { - if (gdc != NULL) { - gdc_wait_for_pending_ops(gdc); - - gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc; - if (vmt != NULL && vmt->release != NULL) { - vmt->release(gdc); - } - } -} - -gdc_size_t gdc_get_size(const gdc_t* gdc) { - if (gdc != NULL) { - gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc; - if (vmt != NULL && vmt->get_bitmap != NULL) { - return vmt->get_bitmap((gdc_t*)gdc)->size; - } - } - - return gdc_size(0, 0); -} - -void gdc_wait_for_pending_ops(gdc_t* gdc) { -#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) - if (gdc != NULL) { - dma2d_wait(); - } -#endif -} - -bool gdc_fill_rect(gdc_t* gdc, gdc_rect_t rect, gdc_color_t color) { - if (gdc != NULL) { - gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc; - - gdc_bitmap_t* bitmap = (gdc_bitmap_t*)gdc; - - gdc_clip_t clip = gdc_clip(rect, bitmap->size, NULL); - - if (clip.width <= 0 || clip.height <= 0) { - return true; - } - - dma2d_params_t dp = { - // Destination bitmap - .height = clip.height, - .width = clip.width, - .dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y, - .dst_x = clip.dst_x, - .dst_y = clip.dst_y, - .dst_stride = bitmap->stride, - - // Source bitmap - .src_fg = color, - .src_alpha = 255, - }; - - gdc_wait_for_pending_ops(gdc); - - if (vmt->fill != NULL) { - return vmt->fill(gdc, &dp); - } - } - - return false; -} - -bool gdc_draw_bitmap(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src) { - if (gdc != NULL) { - gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc; - - gdc_bitmap_t* bitmap = vmt->get_bitmap(gdc); - - gdc_clip_t clip = gdc_clip(rect, bitmap->size, src); - - if (clip.width <= 0 || clip.height <= 0) { - return true; - } - - dma2d_params_t dp = { - // Destination bitmap - .height = clip.height, - .width = clip.width, - .dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y, - .dst_x = clip.dst_x, - .dst_y = clip.dst_y, - .dst_stride = bitmap->stride, - - // Source bitmap - .src_row = - (uint8_t*)src->bitmap->ptr + src->bitmap->stride * clip.src_y, - .src_x = clip.src_x, - .src_y = clip.src_y, - .src_stride = src->bitmap->stride, - .src_fg = src->fg_color, - .src_bg = src->bg_color, - .src_alpha = 255, - }; - - gdc_wait_for_pending_ops(gdc); - - if (src->bitmap->format == GDC_FORMAT_MONO4) { - if (vmt->copy_mono4 != NULL) { - return vmt->copy_mono4(gdc, &dp); - } - } else if (src->bitmap->format == GDC_FORMAT_RGB565) { - if (vmt->copy_rgb565 != NULL) { - return vmt->copy_rgb565(gdc, &dp); - } - } else if (src->bitmap->format == GDC_FORMAT_RGBA8888) { - if (vmt->copy_rgba8888 != NULL) { - return vmt->copy_rgba8888(gdc, &dp); - } - } - } - - return false; -} - -bool gdc_draw_blended(gdc_t* gdc, gdc_rect_t rect, - const gdc_bitmap_ref_t* src) { - if (gdc != NULL) { - gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc; - - gdc_bitmap_t* bitmap = vmt->get_bitmap(gdc); - - gdc_clip_t clip = gdc_clip(rect, bitmap->size, src); - - if (clip.width <= 0 || clip.height <= 0) { - return true; - } - - dma2d_params_t dp = { - // Destination rectangle - .height = clip.height, - .width = clip.width, - .dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y, - .dst_x = clip.dst_x, - .dst_y = clip.dst_y, - .dst_stride = bitmap->stride, - - // Source bitmap - .src_row = - (uint8_t*)src->bitmap->ptr + src->bitmap->stride * clip.src_y, - .src_x = clip.src_x, - .src_y = clip.src_y, - .src_stride = src->bitmap->stride, - .src_fg = src->fg_color, - .src_alpha = 255, - }; - - gdc_wait_for_pending_ops(gdc); - - if (src->bitmap->format == GDC_FORMAT_MONO4) { - if (vmt->blend_mono4 != NULL) { - return vmt->blend_mono4(gdc, &dp); - } - } - } - - return false; -} diff --git a/core/embed/gdc/gdc_core.h b/core/embed/gdc/gdc_core.h deleted file mode 100644 index 7c8b97beb..000000000 --- a/core/embed/gdc/gdc_core.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 GDC_CORE_H -#define GDC_CORE_H - -#include "gdc_bitmap.h" -#include "gdc_color.h" -#include "gdc_dma2d.h" -#include "gdc_geom.h" - -#include -#include -#include - -// ------------------------------------------------------------------------ -// GDC - Graphics Device Context -// - -typedef void gdc_t; - -// ------------------------------------------------------------------------ -// GDC (Graphic Device Context) Virtual Method Table -// -// GDC structure is implementation specific. Only requirement is that -// it starts with a field of type gdc_vmt_t* vmt. -// -// typedef struct -// { -// gdc_vmt_t* vmt; -// -// // GDC specific data -// -// } gdc_impl_specific_t; -// - -typedef void (*gdc_release_t)(gdc_t* gdc); -typedef gdc_bitmap_t* (*gdc_get_bitmap_t)(gdc_t* gdc); -typedef bool (*gdc_fill_t)(gdc_t* gdc, dma2d_params_t* params); -typedef bool (*gdc_copy_mono4_t)(gdc_t* gdc, dma2d_params_t* params); -typedef bool (*gdc_copy_rgb565_t)(gdc_t* gdc, dma2d_params_t* params); -typedef bool (*gdc_copy_rgba8888_t)(gdc_t* gdc, dma2d_params_t* params); -typedef bool (*gdc_blend_mono4_t)(gdc_t* gdc, dma2d_params_t* params); - -// GDC virtual methods -struct gdc_vmt { - gdc_release_t release; - gdc_get_bitmap_t get_bitmap; - gdc_fill_t fill; - gdc_copy_mono4_t copy_mono4; - gdc_copy_rgb565_t copy_rgb565; - gdc_copy_rgba8888_t copy_rgba8888; - gdc_blend_mono4_t blend_mono4; -}; - -// ------------------------------------------------------------------------ -// GDC (Graphic Device Context) Public API - -// Releases reference to GDC -void gdc_release(gdc_t* gdc); - -// Gets size of GDC bounding rectangle -gdc_size_t gdc_get_size(const gdc_t* gdc); - -// Wait for pending DMA operation applied on this GDC -// (used by high level code before accessing GDC's framebuffer/bitmap) -void gdc_wait_for_pending_ops(gdc_t* gdc); - -// Fills a rectangle with a specified color -bool gdc_fill_rect(gdc_t* gdc, gdc_rect_t rect, gdc_color_t color); - -// Draws a bitmap into the specified rectangle -// The destination rectangle may not be fully filled if the source bitmap -// is smaller then destination rectangle or if the bitmap is translated by -// an offset partially or completely outside the destination rectangle. -bool gdc_draw_bitmap(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src); - -// Blends a bitmap with the gdc background in the specified rectangle. -// The destination rectangle may not be fully filled if the source bitmap -// is smaller then destination rectangle or if the bitmap is translated by -// an offset partially or completely outside the destination rectangle. -bool gdc_draw_blended(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src); - -// ------------------------------------------------------------------------ -// this will be defined elsewhere:: - -// Gets GDC for the hardware display -// Returns NULL if display gdc was already acquired and not released -gdc_t* display_acquire_gdc(void); - -#endif // GDC_CORE_H diff --git a/core/embed/gdc/gdc_geom.h b/core/embed/gdc/gdc_geom.h deleted file mode 100644 index 2ffd11c0c..000000000 --- a/core/embed/gdc/gdc_geom.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 GDC_GEOM_H -#define GDC_GEOM_H - -// ------------------------------------------------------------------------ -// GDC Rectangle -// -// used for simplified manipulation with rectangle coordinates - -typedef struct { - int16_t x0; - int16_t y0; - int16_t x1; - int16_t y1; -} gdc_rect_t; - -// Creates a rectangle from top-left coordinates and dimensions -static inline gdc_rect_t gdc_rect_wh(int16_t x, int16_t y, int16_t w, - int16_t h) { - gdc_rect_t rect = { - .x0 = x, - .y0 = y, - .x1 = x + w, - .y1 = y + h, - }; - - return rect; -} - -// Creates a rectangle from top-left and bottom-right coordinates -static inline gdc_rect_t gdc_rect(int16_t x0, int16_t y0, int16_t x1, - int16_t y1) { - gdc_rect_t rect = { - .x0 = x0, - .y0 = y0, - .x1 = x1, - .y1 = y1, - }; - - return rect; -} - -// ------------------------------------------------------------------------ -// GDC Size -// -// used for simplified manipulation with size of objects - -typedef struct { - int16_t x; - int16_t y; -} gdc_size_t; - -// Creates a rectangle from top-left and bottom-right coordinates -static inline gdc_size_t gdc_size(int16_t x, int16_t y) { - gdc_size_t size = { - .x = x, - .y = y, - }; - - return size; -} - -// ------------------------------------------------------------------------ -// GDC Offset -// -// used for simplified manipulation with size of objects - -typedef gdc_size_t gdc_offset_t; - -#endif // GDC_GEOM_H diff --git a/core/embed/gdc/gdc_rgb565.c b/core/embed/gdc/gdc_rgb565.c deleted file mode 100644 index 72bce2002..000000000 --- a/core/embed/gdc/gdc_rgb565.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 "gdc_core.h" -#include "gdc_dma2d.h" -#include "gdc_ops.h" - -#include - -static void gdc_rgb565_release(gdc_t* gdc) { - /* gdc_bitmap_t* bitmap = (gdc_bitmap_t*) gdc; - - if (bitmap->release != NULL) { - bitmap->release(bitmap->context); - }*/ -} - -static gdc_bitmap_t* gdc_rgb565_get_bitmap(gdc_t* gdc) { - return (gdc_bitmap_t*)gdc; -} - -static bool gdc_rgb565_fill(gdc_t* gdc, dma2d_params_t* params) { - return rgb565_fill(params); -} - -static bool gdc_rgb565_copy_mono4(gdc_t* gdc, dma2d_params_t* params) { - return rgb565_copy_mono4(params); -} - -static bool gdc_rgb565_copy_rgb565(gdc_t* gdc, dma2d_params_t* params) { - return rgb565_copy_rgb565(params); -} - -static bool gdc_rgb565_blend_mono4(gdc_t* gdc, dma2d_params_t* params) { - return rgb565_blend_mono4(params); -} - -gdc_bitmap_t gdc_bitmap_rgb565(void* data_ptr, size_t stride, gdc_size_t size, - uint8_t attrs) { - static const gdc_vmt_t gdc_rgb565 = { - .release = gdc_rgb565_release, - .get_bitmap = gdc_rgb565_get_bitmap, - .fill = gdc_rgb565_fill, - .copy_mono4 = gdc_rgb565_copy_mono4, - .copy_rgb565 = gdc_rgb565_copy_rgb565, - .copy_rgba8888 = NULL, - .blend_mono4 = gdc_rgb565_blend_mono4, - }; - - gdc_bitmap_t bitmap = {.vmt = &gdc_rgb565, - .ptr = data_ptr, - .stride = stride, - .size = size, - .format = GDC_FORMAT_RGB565, - .attrs = attrs}; - - return bitmap; -} diff --git a/core/embed/gdc/gdc_rgba8888.c b/core/embed/gdc/gdc_rgba8888.c deleted file mode 100644 index f4481816d..000000000 --- a/core/embed/gdc/gdc_rgba8888.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 "gdc_core.h" - -#include - -static void gdc_rgba8888_release(gdc_t* gdc) { - /* gdc_bitmap_t* bitmap = (gdc_bitmap_t*) gdc; - - if (bitmap->release != NULL) { - bitmap->release(bitmap->context); - }*/ -} - -static gdc_bitmap_t* gdc_rgba8888_get_bitmap(gdc_t* gdc) { - return (gdc_bitmap_t*)gdc; -} - -gdc_bitmap_t gdc_bitmap_rgba8888(void* data_ptr, size_t stride, gdc_size_t size, - uint8_t attrs) { - static const gdc_vmt_t gdc_rgba8888 = { - .release = gdc_rgba8888_release, - .get_bitmap = gdc_rgba8888_get_bitmap, - .fill = NULL, // dma2d_rgba8888_fill, - .copy_mono4 = NULL, // dma2d_rgba8888_copy_mono4, - .copy_rgb565 = NULL, // dma2d_rgba8888_copy_rgb565, - .copy_rgba8888 = NULL, // dma2d_rgba8888_copy_rgba8888, - .blend_mono4 = NULL, // dma2d_rgba8888_blend_mono4_mono4, - }; - - gdc_bitmap_t bitmap = { - .vmt = &gdc_rgba8888, - .ptr = data_ptr, - .stride = stride, - .size = size, - .format = GDC_FORMAT_RGBA8888, - .attrs = attrs, - }; - - return bitmap; -} diff --git a/core/embed/gdc/gdc_text.c b/core/embed/gdc/gdc_text.c deleted file mode 100644 index 3d98e9501..000000000 --- a/core/embed/gdc/gdc_text.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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 "gdc_text.h" - -#include "fonts/fonts.h" - -#if TREZOR_FONT_BPP == 1 -#define GLYPH_FORMAT GDC_FORMAT_MONO1 -#define GLYPH_STRIDE(w) (((w) + 7) / 8) -#elif TREZOR_FONT_BPP == 2 -#error Unsupported TREZOR_FONT_BPP value -#define GLYPH_FORMAT GDC_FORMAT_MONO2 -#define GLYPH_STRIDE(w) (((w) + 3) / 4) -#elif TREZOR_FONT_BPP == 4 -#define GLYPH_FORMAT GDC_FORMAT_MONO4 -#define GLYPH_STRIDE(w) (((w) + 1) / 2) -#elif TREZOR_FONT_BPP == 8 -#error Unsupported TREZOR_FONT_BPP value -#define GLYPH_FORMAT GDC_FORMAT_MONO8 -#define GLYPH_STRIDE(w) (w) -#else -#error Unsupported TREZOR_FONT_BPP value -#endif - -#define GLYPH_WIDTH(g) ((g)[0]) -#define GLYPH_HEIGHT(g) ((g)[1]) -#define GLYPH_ADVANCE(g) ((g)[2]) -#define GLYPH_BEARING_X(g) ((g)[3]) -#define GLYPH_BEARING_Y(g) ((g)[4]) -#define GLYPH_DATA(g) ((void*)&(g)[5]) - -bool gdc_draw_opaque_text(gdc_t* gdc, gdc_rect_t rect, const char* text, - size_t maxlen, const gdc_text_attr_t* attr) { - if (text == NULL) { - return false; - } - - gdc_bitmap_t glyph_bitmap; - glyph_bitmap.vmt = NULL; - glyph_bitmap.format = GLYPH_FORMAT; - - gdc_bitmap_ref_t glyph_ref; - glyph_ref.bitmap = &glyph_bitmap; - glyph_ref.fg_color = attr->fg_color; - glyph_ref.bg_color = attr->bg_color; - - int max_height = font_max_height(attr->font); - int baseline = font_baseline(attr->font); - - int offset_x = attr->offset.x; - - if (offset_x < 0) { - rect.x0 -= attr->offset.x; - offset_x = 0; - } - - for (int i = 0; i < maxlen; i++) { - uint8_t ch = (uint8_t)text[i]; - - if (ch == 0 || rect.x0 >= rect.x1) { - break; - } - - const uint8_t* glyph = font_get_glyph(attr->font, ch); - - if (glyph == NULL) { - continue; - } - - if (offset_x >= GLYPH_ADVANCE(glyph)) { - offset_x -= GLYPH_ADVANCE(glyph); - continue; - } - - glyph_bitmap.ptr = GLYPH_DATA(glyph); - glyph_bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph)); - glyph_bitmap.size.x = GLYPH_WIDTH(glyph); - glyph_bitmap.size.y = GLYPH_HEIGHT(glyph); - - glyph_ref.offset.x = attr->offset.x - GLYPH_BEARING_X(glyph); - glyph_ref.offset.y = - attr->offset.y - (max_height - baseline - GLYPH_BEARING_Y(glyph)); - - if (!gdc_draw_bitmap(gdc, rect, &glyph_ref)) { - return false; - } - - rect.x0 += GLYPH_ADVANCE(glyph) - offset_x; - offset_x = 0; - } - - return true; -} - -bool gdc_draw_blended_text(gdc_t* gdc, gdc_rect_t rect, const char* text, - size_t maxlen, const gdc_text_attr_t* attr) { - if (text == NULL) { - return false; - } - - gdc_bitmap_t glyph_bitmap; - glyph_bitmap.vmt = NULL; - glyph_bitmap.format = GLYPH_FORMAT; - - gdc_bitmap_ref_t glyph_ref; - glyph_ref.bitmap = &glyph_bitmap; - glyph_ref.fg_color = attr->fg_color; - glyph_ref.bg_color = attr->bg_color; - - int max_height = font_max_height(attr->font); - int baseline = font_baseline(attr->font); - - int offset_x = attr->offset.x; - - if (offset_x < 0) { - rect.x0 -= attr->offset.x; - offset_x = 0; - } - - for (int i = 0; i < maxlen; i++) { - uint8_t ch = (uint8_t)text[i]; - - if (ch == 0 || rect.x0 >= rect.x1) { - break; - } - - const uint8_t* glyph = font_get_glyph(attr->font, ch); - - if (glyph == NULL) { - continue; - } - - if (offset_x >= GLYPH_ADVANCE(glyph)) { - offset_x -= GLYPH_ADVANCE(glyph); - continue; - } else { - } - - glyph_bitmap.ptr = GLYPH_DATA(glyph); - glyph_bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph)); - glyph_bitmap.size.x = GLYPH_WIDTH(glyph); - glyph_bitmap.size.y = GLYPH_HEIGHT(glyph); - - glyph_ref.offset.x = offset_x - GLYPH_BEARING_X(glyph); - glyph_ref.offset.y = - attr->offset.y - (max_height - baseline - GLYPH_BEARING_Y(glyph)); - - if (!gdc_draw_blended(gdc, rect, &glyph_ref)) { - return false; - } - - rect.x0 += GLYPH_ADVANCE(glyph) - offset_x; - offset_x = 0; - } - - return true; -} diff --git a/core/embed/gdc/gdc_wnd565.c b/core/embed/gdc/gdc_wnd565.c deleted file mode 100644 index 6e008ea81..000000000 --- a/core/embed/gdc/gdc_wnd565.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 "gdc_wnd565.h" -#include "gdc_ops.h" - -#include - -#include "display.h" - -static void gdc_wnd565_release(gdc_t* gdc) { - // gdc_wnd565_t* wnd = (gdc_wnd565_t*)gdc; - - // if (wnd->config.release != NULL) { - // wnd->config.release(wnd->config.context); - // } -} - -static gdc_bitmap_t* gdc_wnd565_get_bitmap(gdc_t* gdc) { - return &((gdc_wnd565_t*)gdc)->bitmap; -} - -static bool gdc_wnd565_fill(gdc_t* gdc, dma2d_params_t* params) { - return wnd565_fill(params); -} - -static bool gdc_wnd565_copy_rgb565(gdc_t* gdc, dma2d_params_t* params) { - return wnd565_copy_rgb565(params); -} - -gdc_t* gdc_wnd565_init(gdc_wnd565_t* gdc, gdc_wnd565_config_t* config) { - static const gdc_vmt_t gdc_wnd565 = { - .release = gdc_wnd565_release, - .get_bitmap = gdc_wnd565_get_bitmap, - .fill = gdc_wnd565_fill, - .copy_mono4 = NULL, // gdc_wnd565_copy_mono4, - .copy_rgb565 = gdc_wnd565_copy_rgb565, - .copy_rgba8888 = NULL, - .blend_mono4 = NULL, - }; - - memset(gdc, 0, sizeof(gdc_wnd565_t)); - gdc->vmt = &gdc_wnd565; - gdc->bitmap.format = GDC_FORMAT_RGB565; - gdc->bitmap.size = config->size; - gdc->bitmap.ptr = (void*)config->reg_address; - - return (gdc_t*)&gdc->vmt; -} - -gdc_t* display_acquire_gdc(void) { - static gdc_wnd565_t wnd = {}; - - if (wnd.vmt == NULL) { - gdc_wnd565_config_t config = { - .size.x = 240, - .size.y = 240, - }; - gdc_wnd565_init(&wnd, &config); - } - - return (gdc_t*)&wnd.vmt; -} diff --git a/core/embed/gdc/gdc_wnd565.h b/core/embed/gdc/gdc_wnd565.h deleted file mode 100644 index e55bfb883..000000000 --- a/core/embed/gdc/gdc_wnd565.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 GDC_WND565_H -#define GDC_WND565_H - -#include "gdc_core.h" - -// ------------------------------------------------------------------------ -// GDC for displays RGB565 with register/window API like ST7789 -// -// This module serves as a driver for specific types of displays with -// internal memory acting as a frame buffer and a specific interface -// for writing to this framebuffer by putting pixels into the -// specified rectangle window. - -typedef void (*gdc_release_cb_t)(void* context); - -// Driver configuration -typedef struct { - // TODO - uintptr_t reg_address; - - // GDC size in pixels - gdc_size_t size; - - // Release callback invoked when gdc_release() is called - gdc_release_cb_t release; - // Context for release callback - void* context; - -} gdc_wnd565_config_t; - -// Driver-specific GDC structure -typedef struct { - // GDC virtual method table - // (Must be the first field of the structure) - const gdc_vmt_t* vmt; - - // Fake bitmap structure - gdc_bitmap_t bitmap; - - // Current drawing window/rectangle - gdc_rect_t rect; - // Cursor position in the window - int cursor_x; - int cursor_y; - -} gdc_wnd565_t; - -// Initializes GDC context -gdc_t* gdc_wnd565_init(gdc_wnd565_t* gdc, gdc_wnd565_config_t* config); - -#endif // GDC_WND565_H diff --git a/core/embed/gdc/gdc_wnd565_ops.c b/core/embed/gdc/gdc_wnd565_ops.c deleted file mode 100644 index d894f7316..000000000 --- a/core/embed/gdc/gdc_wnd565_ops.c +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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 "gdc_ops.h" - -#include "display.h" - -static void set_window(const dma2d_params_t* dp) { - display_set_window(dp->dst_x, dp->dst_y, dp->dst_x + dp->width - 1, - dp->dst_y + dp->height + 1); -} - -bool wnd565_fill(const dma2d_params_t* dp) { - set_window(dp); - - uint16_t height = dp->height; - - while (height-- > 0) { - for (int x = 0; x < dp->width; x++) { - PIXELDATA(dp->src_fg); - } - } - - return true; -} - -bool wnd565_copy_rgb565(const dma2d_params_t* dp) { - set_window(dp); - - uint16_t* src_ptr = (uint16_t*)dp->src_row + dp->src_x; - uint16_t height = dp->height; - - while (height-- > 0) { - for (int x = 0; x < dp->width; x++) { - PIXELDATA(src_ptr[x]); - } - src_ptr += dp->src_stride / sizeof(*src_ptr); - } - - return true; -} diff --git a/core/embed/lib/display_draw.c b/core/embed/lib/display_draw.c index 608fabe42..138155ebb 100644 --- a/core/embed/lib/display_draw.c +++ b/core/embed/lib/display_draw.c @@ -61,8 +61,8 @@ void display_clear(void) { // set MADCTL first so that we can set the window correctly next display_orientation(0); // address the complete frame memory - display_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1); - for (uint32_t i = 0; i < MAX_DISPLAY_RESX * MAX_DISPLAY_RESY; i++) { + display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { // 2 bytes per pixel because we're using RGB 5-6-5 format PIXELDATA(0x0000); } diff --git a/core/embed/gdc/gdc_color.c b/core/embed/lib/gl_color.c similarity index 52% rename from core/embed/gdc/gdc_color.c rename to core/embed/lib/gl_color.c index 6ebbf94c3..ec943ad4b 100644 --- a/core/embed/gdc/gdc_color.c +++ b/core/embed/lib/gl_color.c @@ -17,33 +17,33 @@ * along with this program. If not, see . */ -#include "gdc_color.h" +#include "gl_color.h" #include "colors.h" -const gdc_color16_t* gdc_color16_gradient_a4(gdc_color_t fg_color, - gdc_color_t bg_color) { - static gdc_color16_t cache[16] = {0}; +const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg_color, + gl_color_t bg_color) { + static gl_color16_t cache[16] = {0}; - if (gdc_color_to_color16(bg_color) != cache[0] || - gdc_color_to_color16(fg_color) != cache[15]) { + if (gl_color_to_color16(bg_color) != cache[0] || + gl_color_to_color16(fg_color) != cache[15]) { for (int alpha = 0; alpha < 16; alpha++) { - cache[alpha] = gdc_color16_blend_a4(fg_color, bg_color, alpha); + cache[alpha] = gl_color16_blend_a4(fg_color, bg_color, alpha); } } - return (const gdc_color16_t*)&cache[0]; + return (const gl_color16_t*)&cache[0]; } -const gdc_color32_t* gdc_color32_gradient_a4(gdc_color_t fg_color, - gdc_color_t bg_color) { - static gdc_color32_t cache[16] = {0}; +const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg_color, + gl_color_t bg_color) { + static gl_color32_t cache[16] = {0}; - if (bg_color != gdc_color32_to_color(cache[0]) || - fg_color != gdc_color32_to_color(cache[15])) { + if (bg_color != gl_color32_to_color(cache[0]) || + fg_color != gl_color32_to_color(cache[15])) { for (int alpha = 0; alpha < 16; alpha++) { - cache[alpha] = gdc_color32_blend_a4(fg_color, bg_color, alpha); + cache[alpha] = gl_color32_blend_a4(fg_color, bg_color, alpha); } } - return (const gdc_color32_t*)&cache[0]; + return (const gl_color32_t*)&cache[0]; } \ No newline at end of file diff --git a/core/embed/gdc/gdc_color.h b/core/embed/lib/gl_color.h similarity index 72% rename from core/embed/gdc/gdc_color.h rename to core/embed/lib/gl_color.h index fb670fde5..83d25a251 100644 --- a/core/embed/gdc/gdc_color.h +++ b/core/embed/lib/gl_color.h @@ -17,13 +17,13 @@ * along with this program. If not, see . */ -#ifndef GDC_COLOR_H -#define GDC_COLOR_H +#ifndef GL_COLOR_H +#define GL_COLOR_H #include -#define GDC_COLOR_16BIT -// #define GDC_COLOR_32BIT +#define GL_COLOR_16BIT +// #define GL_COLOR_32BIT // Color in RGB565 format // @@ -32,7 +32,7 @@ // |r r r r r g g g | g g g b b b b b| // |---------------------------------| -typedef uint16_t gdc_color16_t; +typedef uint16_t gl_color16_t; // Color in RGBA8888 format // @@ -42,40 +42,40 @@ typedef uint16_t gdc_color16_t; // |----------------------------------------------------------------------| // -typedef uint32_t gdc_color32_t; - -#ifdef GDC_COLOR_16BIT -#define gdc_color_t gdc_color16_t -#define gdc_color_to_color16(c) (c) -#define gdc_color16_to_color(c) (c) -#define gdc_color_to_color32(c) (gdc_color16_to_color32(c)) -#define gdc_color32_to_color(c) (gdc_color32_to_color16(c)) -#define gdc_color_lum(c) (gdc_color16_lum(c)) -#elif GDC_COLOR_32BIT -#define gdc_color_t gdc_color32_t -#define gdc_color_to_color16(c) (gdc_color32_to_color16(c)) -#define gdc_color16_to_color(c) (gdc_color16_to_color32(c)) -#define gdc_color_to_color32(c) (c) -#define gdc_color32_to_color(c) (c) +typedef uint32_t gl_color32_t; + +#ifdef GL_COLOR_16BIT +#define gl_color_t gl_color16_t +#define gl_color_to_color16(c) (c) +#define gl_color16_to_color(c) (c) +#define gl_color_to_color32(c) (gl_color16_to_color32(c)) +#define gl_color32_to_color(c) (gl_color32_to_color16(c)) +#define gl_color_lum(c) (gl_color16_lum(c)) +#elif GL_COLOR_32BIT +#define gl_color_t gl_color32_t +#define gl_color_to_color16(c) (gl_color32_to_color16(c)) +#define gl_color16_to_color(c) (gl_color16_to_color32(c)) +#define gl_color_to_color32(c) (c) +#define gl_color32_to_color(c) (c) #else -#error "GDC_COLOR_16BIT/32BIT not specified" +#error "GL_COLOR_16BIT/32BIT not specified" #endif // Constructs a 16-bit color from the given red (r), // green (g), and blue (b) values in the range 0..255 -static inline gdc_color16_t gdc_color16_rgb(uint8_t r, uint8_t g, uint8_t b) { +static inline gl_color16_t gl_color16_rgb(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8U) << 8) | ((g & 0xFCU) << 3) | ((b & 0xF8U) >> 3); } // Constructs a 32-bit color from the given red (r), // green (g), and blue (b) values in the range 0..255. // Alpha is set to 255. -static inline gdc_color32_t gdc_color32_rgb(uint8_t r, uint8_t g, uint8_t b) { +static inline gl_color32_t gl_color32_rgb(uint8_t r, uint8_t g, uint8_t b) { return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } // Converts a 16-bit color to a 32-bit color; alpha is set to 255 -static inline gdc_color32_t gdc_color16_to_color32(gdc_color16_t color) { +static inline gl_color32_t gl_color16_to_color32(gl_color16_t color) { uint32_t r = (color & 0xF800) >> 8; uint32_t g = (color & 0x07E0) >> 3; uint32_t b = (color & 0x001F) << 3; @@ -88,7 +88,7 @@ static inline gdc_color32_t gdc_color16_to_color32(gdc_color16_t color) { } // Converts 32-bit color to 16-bit color, alpha is ignored -static inline gdc_color16_t gdc_color32_to_color16(gdc_color32_t color) { +static inline gl_color16_t gl_color32_to_color16(gl_color32_t color) { uint16_t r = (color & 0x00F80000) >> 8; uint16_t g = (color & 0x0000FC00) >> 5; uint16_t b = (color & 0x000000F8) >> 3; @@ -97,7 +97,7 @@ static inline gdc_color16_t gdc_color32_to_color16(gdc_color32_t color) { } // Converts 16-bit color into luminance (ranging from 0 to 255) -static inline uint8_t gdc_color_lum(gdc_color16_t color) { +static inline uint8_t gl_color_lum(gl_color16_t color) { uint16_t r = (color & 0x00F80000) >> 8; uint16_t g = (color & 0x0000FC00) >> 5; uint16_t b = (color & 0x000000F8) >> 3; @@ -105,16 +105,15 @@ static inline uint8_t gdc_color_lum(gdc_color16_t color) { return (r + g + b) / 3; } -#ifdef GDC_COLOR_16BIT +#ifdef GL_COLOR_16BIT // Blends foreground and background colors with 4-bit alpha // // Returns a color in 16-bit format // // If alpha is 0, the function returns the background color // If alpha is 15, the function returns the foreground color -static inline gdc_color16_t gdc_color16_blend_a4(gdc_color16_t fg, - gdc_color16_t bg, - uint8_t alpha) { +static inline gl_color16_t gl_color16_blend_a4(gl_color16_t fg, gl_color16_t bg, + uint8_t alpha) { uint16_t fg_r = (fg & 0xF800) >> 11; uint16_t bg_r = (bg & 0xF800) >> 11; @@ -137,9 +136,8 @@ static inline gdc_color16_t gdc_color16_blend_a4(gdc_color16_t fg, // // If alpha is 0, the function returns the background color // If alpha is 15, the function returns the foreground color -static inline gdc_color16_t gdc_color16_blend_a8(gdc_color16_t fg, - gdc_color16_t bg, - uint8_t alpha) { +static inline gl_color16_t gl_color16_blend_a8(gl_color16_t fg, gl_color16_t bg, + uint8_t alpha) { uint16_t fg_r = (fg & 0xF800) >> 11; uint16_t bg_r = (bg & 0xF800) >> 11; @@ -162,9 +160,8 @@ static inline gdc_color16_t gdc_color16_blend_a8(gdc_color16_t fg, // // If alpha is 0, the function returns the background color // If alpha is 15, the function returns the foreground color -static inline gdc_color32_t gdc_color32_blend_a4(gdc_color16_t fg, - gdc_color16_t bg, - uint8_t alpha) { +static inline gl_color32_t gl_color32_blend_a4(gl_color16_t fg, gl_color16_t bg, + uint8_t alpha) { uint16_t fg_r = (fg & 0xF800) >> 8; fg_r |= fg_r >> 5; uint16_t bg_r = (bg & 0xF800) >> 8; @@ -187,7 +184,7 @@ static inline gdc_color32_t gdc_color32_blend_a4(gdc_color16_t fg, return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } -#elif GDC_COLOR_32BIT +#elif GL_COLOR_32BIT // Blends foreground and background colors with 4-bit alpha // @@ -195,9 +192,8 @@ static inline gdc_color32_t gdc_color32_blend_a4(gdc_color16_t fg, // // If alpha is 0, the function returns the background color // If alpha is 15, the function returns the foreground color -static inline gdc_color16_t gdc_color16_blend_a4(gdc_color32_t fg, - gdc_color32_t bg, - uint8_t alpha) { +static inline gl_color16_t gl_color16_blend_a4(gl_color32_t fg, gl_color32_t bg, + uint8_t alpha) { uint16_t fg_r = (fg & 0x00FF0000) >> 16; uint16_t bg_r = (bg & 0x00FF0000) >> 16; uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15; @@ -210,7 +206,7 @@ static inline gdc_color16_t gdc_color16_blend_a4(gdc_color32_t fg, uint16_t bg_b = (bg & 0x000000FF) >> 0; uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15; - return gdc_color16_rgb(r, g, b) + return gl_color16_rgb(r, g, b) } // Blends foreground and background colors with 8-bit alpha @@ -219,9 +215,8 @@ static inline gdc_color16_t gdc_color16_blend_a4(gdc_color32_t fg, // // If alpha is 0, the function returns the background color // If alpha is 255, the function returns the foreground color -static inline gdc_color16_t gdc_color16_blend_a8(gdc_color32_t fg, - gdc_color32_t bg, - uint8_t alpha) { +static inline gl_color16_t gl_color16_blend_a8(gl_color32_t fg, gl_color32_t bg, + uint8_t alpha) { uint16_t fg_r = (fg & 0x00FF0000) >> 16; uint16_t bg_r = (bg & 0x00FF0000) >> 16; uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255; @@ -234,19 +229,17 @@ static inline gdc_color16_t gdc_color16_blend_a8(gdc_color32_t fg, uint16_t bg_b = (bg & 0x000000FF) >> 0; uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255; - return gdc_color16_rgb(r, g, b) + return gl_color16_rgb(r, g, b) } - // Blends foreground and background colors with 4-bit alpha // // Returns a color in 32-bit format // // If alpha is 0, the function returns the background color // If alpha is 15, the function returns the foreground color -static inline gdc_color32_t gdc_color32_blend_a4(gdc_color32_t fg, - gdc_color32_t bg, - uint8_t alpha) { +static inline gl_color32_t gl_color32_blend_a4(gl_color32_t fg, gl_color32_t bg, + uint8_t alpha) { uint16_t fg_r = (fg & 0x00FF0000) >> 16; uint16_t bg_r = (bg & 0x00FF0000) >> 16; uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15; @@ -259,23 +252,23 @@ static inline gdc_color32_t gdc_color32_blend_a4(gdc_color32_t fg, uint16_t bg_b = (bg & 0x000000FF) >> 0; uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15; - return gdc_color32_rgb(r, g, b); + return gl_color32_rgb(r, g, b); } #else -#error "GDC_COLOR_16BIT/32BIT not specified" +#error "GL_COLOR_16BIT/32BIT not specified" #endif // Returns a gradient as an array of 16 consecutive 16-bit colors // // Each element in the array represents a color, with retval[0] being // the background (bg) color and retval[15] the foreground (fg) color -const gdc_color16_t* gdc_color16_gradient_a4(gdc_color_t fg, gdc_color_t bg); +const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg, gl_color_t bg); // Returns a gradient as an array of 16 consecutive 32-bit colors // // Each element in the array represents a color, with retval[0] being // the background (bg) color and retval[15] the foreground (fg) color -const gdc_color32_t* gdc_color32_gradient_a4(gdc_color_t fg, gdc_color_t bg); +const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg, gl_color_t bg); -#endif // TREZORHAL_GDC_COLOR_H +#endif // TREZORHAL_GL_COLOR_H diff --git a/core/embed/gdc/gdc_ops.h b/core/embed/lib/gl_dma2d.h similarity index 70% rename from core/embed/gdc/gdc_ops.h rename to core/embed/lib/gl_dma2d.h index 7efd32e20..32ecae726 100644 --- a/core/embed/gdc/gdc_ops.h +++ b/core/embed/lib/gl_dma2d.h @@ -17,7 +17,36 @@ * along with this program. If not, see . */ -#include "gdc_dma2d.h" +#ifndef GL_DMA2D_H +#define GL_DMA2D_H + +#include +#include + +#include "gl_color.h" + +typedef struct { + // Destination bitma[ + // Following fields are used for all operations + uint16_t height; + uint16_t width; + void* dst_row; + uint16_t dst_x; + uint16_t dst_y; + uint16_t dst_stride; + + // Source bitmap + // Used for copying and blending, but src_fg & src_alpha + // fields are also used for fill operation + void* src_row; + uint16_t src_x; + uint16_t src_y; + uint16_t src_stride; + gl_color_t src_fg; + gl_color_t src_bg; + uint8_t src_alpha; + +} dma2d_params_t; bool rgb565_fill(const dma2d_params_t* dp); bool rgb565_copy_mono4(const dma2d_params_t* dp); @@ -36,5 +65,4 @@ bool mono8_copy_mono4(const dma2d_params_t* dp); bool mono8_blend_mono1p(const dma2d_params_t* dp); bool mono8_blend_mono4(const dma2d_params_t* dp); -bool wnd565_fill(const dma2d_params_t* dp); -bool wnd565_copy_rgb565(const dma2d_params_t* dp); +#endif // GL_DMA2D_H \ No newline at end of file diff --git a/core/embed/gdc/gdc_mono8_ops.c b/core/embed/lib/gl_dma2d_mono8.c similarity index 90% rename from core/embed/gdc/gdc_mono8_ops.c rename to core/embed/lib/gl_dma2d_mono8.c index 86f479aa6..b385d0a57 100644 --- a/core/embed/gdc/gdc_mono8_ops.c +++ b/core/embed/lib/gl_dma2d_mono8.c @@ -17,14 +17,13 @@ * along with this program. If not, see . */ -#include "gdc_color.h" -#include "gdc_ops.h" +#include "gl_dma2d.h" bool mono8_fill(const dma2d_params_t* dp) { uint8_t* dst_ptr = (uint8_t*)dp->dst_row + dp->dst_x; uint16_t height = dp->height; - uint8_t fg = gdc_color_lum(dp->src_fg); + uint8_t fg = gl_color_lum(dp->src_fg); while (height-- > 0) { for (int x = 0; x < dp->width; x++) { @@ -42,8 +41,8 @@ bool mono8_copy_mono1p(const dma2d_params_t* dp) { uint16_t src_ofs = dp->src_stride * dp->src_y + dp->src_x; uint16_t height = dp->height; - uint8_t fg = gdc_color_lum(dp->src_fg); - uint8_t bg = gdc_color_lum(dp->src_bg); + uint8_t fg = gl_color_lum(dp->src_fg); + uint8_t bg = gl_color_lum(dp->src_bg); while (height-- > 0) { for (int x = 0; x < dp->width; x++) { @@ -63,8 +62,8 @@ bool mono8_copy_mono4(const dma2d_params_t* dp) { uint8_t* src_row = (uint8_t*)dp->src_row; uint16_t height = dp->height; - uint8_t fg = gdc_color_lum(dp->src_fg); - uint8_t bg = gdc_color_lum(dp->src_bg); + uint8_t fg = gl_color_lum(dp->src_fg); + uint8_t bg = gl_color_lum(dp->src_bg); while (height-- > 0) { for (int x = 0; x < dp->width; x++) { @@ -85,7 +84,7 @@ bool mono8_blend_mono1p(const dma2d_params_t* dp) { uint16_t src_ofs = dp->src_stride * dp->src_y + dp->src_x; uint16_t height = dp->height; - uint8_t fg = gdc_color_lum(dp->src_fg); + uint8_t fg = gl_color_lum(dp->src_fg); while (height-- > 0) { for (int x = 0; x < dp->width; x++) { @@ -105,7 +104,7 @@ bool mono8_blend_mono4(const dma2d_params_t* dp) { uint8_t* src_row = (uint8_t*)dp->src_row; uint16_t height = dp->height; - uint8_t fg = gdc_color_lum(dp->src_fg); + uint8_t fg = gl_color_lum(dp->src_fg); while (height-- > 0) { for (int x = 0; x < dp->width; x++) { diff --git a/core/embed/gdc/gdc_rgb565_ops.c b/core/embed/lib/gl_dma2d_rgb565.c similarity index 91% rename from core/embed/gdc/gdc_rgb565_ops.c rename to core/embed/lib/gl_dma2d_rgb565.c index 48eb3f1e3..b6f4a2d2d 100644 --- a/core/embed/gdc/gdc_rgb565_ops.c +++ b/core/embed/lib/gl_dma2d_rgb565.c @@ -17,8 +17,7 @@ * along with this program. If not, see . */ -#include "gdc_dma2d.h" -#include "gdc_ops.h" +#include "gl_dma2d.h" #if USE_DMA2D #include "dma2d.h" @@ -41,12 +40,11 @@ bool rgb565_fill(const dma2d_params_t* dp) { } dst_ptr += dp->dst_stride / sizeof(*dst_ptr); } - } - else { + } else { uint8_t alpha = dp->src_alpha; while (height-- > 0) { for (int x = 0; x < dp->width; x++) { - dst_ptr[x] = gdc_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha); + dst_ptr[x] = gl_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha); } dst_ptr += dp->dst_stride / sizeof(*dst_ptr); } @@ -62,8 +60,8 @@ bool rgb565_copy_mono4(const dma2d_params_t* dp) { } else #endif { - const gdc_color16_t* gradient = - gdc_color16_gradient_a4(dp->src_fg, dp->src_bg); + const gl_color16_t* gradient = + gl_color16_gradient_a4(dp->src_fg, dp->src_bg); uint16_t* dst_ptr = (uint16_t*)dp->dst_row + dp->dst_x; uint8_t* src_row = (uint8_t*)dp->src_row; @@ -121,8 +119,8 @@ bool rgb565_blend_mono4(const dma2d_params_t* dp) { for (int x = 0; x < dp->width; x++) { uint8_t fg_data = src_row[(x + dp->src_x) / 2]; uint8_t fg_alpha = (x + dp->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F; - dst_ptr[x] = gdc_color16_blend_a4( - dp->src_fg, gdc_color16_to_color(dst_ptr[x]), fg_alpha); + dst_ptr[x] = gl_color16_blend_a4( + dp->src_fg, gl_color16_to_color(dst_ptr[x]), fg_alpha); } dst_ptr += dp->dst_stride / sizeof(*dst_ptr); src_row += dp->src_stride / sizeof(*src_row); diff --git a/core/embed/lib/gl_draw.c b/core/embed/lib/gl_draw.c new file mode 100644 index 000000000..cb6addc09 --- /dev/null +++ b/core/embed/lib/gl_draw.c @@ -0,0 +1,226 @@ +/* + * 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 "display_draw.h" +#include "fonts/fonts.h" +#include "gl_draw.h" + +typedef struct { + int16_t dst_x; + int16_t dst_y; + int16_t src_x; + int16_t src_y; + int16_t width; + int16_t height; +} gl_clip_t; + +static inline gl_clip_t gl_clip(gl_rect_t dst, const gl_bitmap_t* bitmap) { + int16_t dst_x = dst.x0; + int16_t dst_y = dst.y0; + + int16_t src_x = 0; + int16_t src_y = 0; + + if (bitmap != NULL) { + src_x += bitmap->offset.x; + src_y += bitmap->offset.y; + + // Normalize negative x-offset of bitmap + if (src_x < 0) { + dst_x -= src_x; + src_x = 0; + } + + // Normalize negative y-offset of src bitmap + if (src_y < 0) { + dst_y -= src_y; + src_y = 0; + } + } + + // Normalize negative top-left of destination rectangle + if (dst_x < 0) { + src_x -= dst_x; + dst_x = 0; + } + + if (dst_y < 0) { + src_y -= dst_y; + dst_y = 0; + } + + // Calculate dimension of effective rectangle + int16_t width = MIN(DISPLAY_RESX, dst.x1) - dst_x; + int16_t height = MIN(DISPLAY_RESY, dst.y1) - dst_y; + + if (bitmap != NULL) { + width = MIN(width, bitmap->size.x - src_x); + height = MIN(height, bitmap->size.y - src_y); + } + + gl_clip_t clip = { + .dst_x = dst_x, + .dst_y = dst_y, + .src_x = src_x, + .src_y = src_y, + .width = width, + .height = height, + }; + + return clip; +} + +void gl_draw_bar(gl_rect_t rect, gl_color_t color) { + gl_clip_t clip = gl_clip(rect, NULL); + + if (clip.width <= 0 || clip.height <= 0) { + return; + } + + dma2d_params_t dp = { + // Destination bitmap + .height = clip.height, + .width = clip.width, + .dst_row = NULL, + .dst_x = clip.dst_x, + .dst_y = clip.dst_y, + .dst_stride = 0, + + // Source bitmap + .src_fg = color, + .src_alpha = 255, + }; + + display_fill(&dp); +} + +void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap) { + gl_clip_t clip = gl_clip(rect, bitmap); + + if (clip.width <= 0 || clip.height <= 0) { + return; + } + + dma2d_params_t dp = { + // Destination bitmap + .height = clip.height, + .width = clip.width, + .dst_row = NULL, + .dst_x = clip.dst_x, + .dst_y = clip.dst_y, + .dst_stride = 0, + + // Source bitmap + .src_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.src_y, + .src_x = clip.src_x, + .src_y = clip.src_y, + .src_stride = bitmap->stride, + .src_fg = bitmap->fg_color, + .src_bg = bitmap->bg_color, + .src_alpha = 255, + }; + +#if TREZOR_FONT_BPP == 1 + if (bitmap->format == GL_FORMAT_MONO1P) { + display_copy_mono1p(&dp); + } +#endif +#if TREZOR_FONT_BPP == 4 + if (bitmap->format == GL_FORMAT_MONO4) { + display_copy_mono4(&dp); + } +#endif +} + +#if TREZOR_FONT_BPP == 1 +#define GLYPH_FORMAT GL_FORMAT_MONO1P +#define GLYPH_STRIDE(w) (((w) + 7) / 8) +#elif TREZOR_FONT_BPP == 2 +#error Unsupported TREZOR_FONT_BPP value +#define GLYPH_FORMAT GL_FORMAT_MONO2 +#define GLYPH_STRIDE(w) (((w) + 3) / 4) +#elif TREZOR_FONT_BPP == 4 +#define GLYPH_FORMAT GL_FORMAT_MONO4 +#define GLYPH_STRIDE(w) (((w) + 1) / 2) +#elif TREZOR_FONT_BPP == 8 +#error Unsupported TREZOR_FONT_BPP value +#define GLYPH_FORMAT GL_FORMAT_MONO8 +#define GLYPH_STRIDE(w) (w) +#else +#error Unsupported TREZOR_FONT_BPP value +#endif + +#define GLYPH_WIDTH(g) ((g)[0]) +#define GLYPH_HEIGHT(g) ((g)[1]) +#define GLYPH_ADVANCE(g) ((g)[2]) +#define GLYPH_BEARING_X(g) ((g)[3]) +#define GLYPH_BEARING_Y(g) ((g)[4]) +#define GLYPH_DATA(g) ((void*)&(g)[5]) + +void gl_draw_text(gl_rect_t rect, const char* text, size_t maxlen, + const gl_text_attr_t* attr) { + if (text == NULL) { + return; + } + + gl_bitmap_t bitmap = { + .format = GLYPH_FORMAT, + .fg_color = attr->fg_color, + .bg_color = attr->bg_color, + }; + + int max_height = font_max_height(attr->font); + int baseline = font_baseline(attr->font); + + for (int i = 0; i < maxlen; i++) { + uint8_t ch = (uint8_t)text[i]; + + if (ch == 0 || rect.x0 >= rect.x1) { + break; + } + + const uint8_t* glyph = font_get_glyph(attr->font, ch); + + if (glyph == NULL) { + continue; + } + + bitmap.ptr = GLYPH_DATA(glyph); + bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph)); + bitmap.size.x = GLYPH_WIDTH(glyph); + bitmap.size.y = GLYPH_HEIGHT(glyph); + + bitmap.offset.x = -GLYPH_BEARING_X(glyph); + bitmap.offset.y = -(max_height - baseline - GLYPH_BEARING_Y(glyph)); + + gl_draw_bitmap(rect, &bitmap); + + rect.x0 += GLYPH_ADVANCE(glyph); + } +} + +// =============================================================== +// emulation of legacy functions + +void display_bar(int x, int y, int w, int h, uint16_t c) {} + +void display_text(int x, int y, const char* text, int textlen, int font, + uint16_t fgcolor, uint16_t bgcolor) {} diff --git a/core/embed/lib/gl_draw.h b/core/embed/lib/gl_draw.h new file mode 100644 index 000000000..8c9d36b2d --- /dev/null +++ b/core/embed/lib/gl_draw.h @@ -0,0 +1,135 @@ +/* + * 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 GL_DRAW_H +#define GL_DRAW_H + +#include "gl_color.h" + +// 2D rectangle coordinates (x1, y1 point is not included) +typedef struct { + int16_t x0; + int16_t y0; + int16_t x1; + int16_t y1; +} gl_rect_t; + +// Creates a rectangle from top-left coordinates and dimensions +static inline gl_rect_t gl_rect_wh(int16_t x, int16_t y, int16_t w, int16_t h) { + gl_rect_t rect = { + .x0 = x, + .y0 = y, + .x1 = x + w, + .y1 = y + h, + }; + + return rect; +} + +// Creates a rectangle from top-left and bottom-right coordinates +static inline gl_rect_t gl_rect(int16_t x0, int16_t y0, int16_t x1, + int16_t y1) { + gl_rect_t rect = { + .x0 = x0, + .y0 = y0, + .x1 = x1, + .y1 = y1, + }; + + return rect; +} + +// 2D offset/ coordinates +typedef struct { + int16_t x; + int16_t y; +} gl_offset_t; + +static inline gl_offset_t gl_offset(int16_t x, int16_t y) { + gl_offset_t size = { + .x = x, + .y = y, + }; + + return size; +} + +// 2D size in pixels +typedef struct { + int16_t x; + int16_t y; +} gl_size_t; + +static inline gl_size_t gl_size(int16_t x, int16_t y) { + gl_size_t size = { + .x = x, + .y = y, + }; + + return size; +} + +// Bitmap pixel format +typedef enum { + GL_FORMAT_UNKNOWN, // + GL_FORMAT_MONO1P, // 1-bpp per pixel (packed) + GL_FORMAT_MONO4, // 4-bpp per pixel + GL_FORMAT_RGB565, // 16-bpp per pixel + GL_FORMAT_RGBA8888, // 32-bpp +} gl_format_t; + +// 2D bitmap references +typedef struct { + // pointer to top-left pixel + void* ptr; + // stride in bytes + size_t stride; + // size in pixels + gl_size_t size; + // format of pixels, GL_FORMAT_xxx + uint8_t format; + // offset used when bitmap is drawed using gl_draw_bitmap() + gl_offset_t offset; + // foreground color (used with MONOx formats) + gl_color_t fg_color; + // background color (used with MONOx formats) + gl_color_t bg_color; +} gl_bitmap_t; + +// Text attributes +typedef struct { + int font; + gl_color_t fg_color; + gl_color_t bg_color; +} gl_text_attr_t; + +// Fills a rectangle with a specified color +void gl_draw_bar(gl_rect_t rect, gl_color_t color); + +// Draws a bitmap into the specified rectangle +// The destination rectangle may not be fully filled if the source bitmap +// is smaller then destination rectangle or if the bitmap is translated by +// an offset partially or completely outside the destination rectangle. +void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap); + +// !@# TODO +void gl_draw_text(gl_rect_t rect, const char* text, size_t maxlen, + const gl_text_attr_t* attr); + +#endif // GL_DRAW_H diff --git a/core/embed/lib/terminal.c b/core/embed/lib/terminal.c index 9411cbdff..1f1625306 100644 --- a/core/embed/lib/terminal.c +++ b/core/embed/lib/terminal.c @@ -77,6 +77,9 @@ void term_print(const char *text, int textlen) { } } +#ifdef NEW_RENDERING + // TODO !@# +#else // render buffer to display display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { @@ -105,6 +108,7 @@ void term_print(const char *text, int textlen) { } display_pixeldata_dirty(); display_refresh(); +#endif } #ifdef TREZOR_EMULATOR diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml index 2381cdfa7..0ae540760 100644 --- a/core/embed/rust/Cargo.toml +++ b/core/embed/rust/Cargo.toml @@ -14,6 +14,10 @@ micropython = [] protobuf = ["micropython"] ui = [] dma2d = [] +xframebuffer = [] +display_mono = [] +display_rgb565 = [] +display_rgba8888 = [] framebuffer = [] framebuffer32bit = [] ui_debug = [] diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index 96391af6c..601d2fede 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -110,6 +110,16 @@ fn prepare_bindings() -> bindgen::Builder { format!("-DTREZOR_BOARD=\"{}\"", board()).as_str(), ]); + #[cfg(feature = "xframebuffer")] + { + bindings = bindings.clang_args(&["-DXFRAMEBUFFER"]); + } + + #[cfg(feature = "new_rendering")] + { + bindings = bindings.clang_args(["-DNEW_RENDERING"]); + } + // Pass in correct include paths and defines. if is_firmware() { let mut clang_args: Vec<&str> = Vec::new(); @@ -338,6 +348,9 @@ fn generate_trezorhal_bindings() { .allowlist_var("DISPLAY_FRAMEBUFFER_OFFSET_Y") .allowlist_var("DISPLAY_RESX") .allowlist_var("DISPLAY_RESY") + .allowlist_function("display_get_frame_addr") + .allowlist_function("display_fill") + .allowlist_function("display_copy_rgb565") // dma2d .allowlist_type("dma2d_params_t") .allowlist_function("rgb565_fill") @@ -354,8 +367,6 @@ fn generate_trezorhal_bindings() { .allowlist_function("mono8_copy_mono4") .allowlist_function("mono8_blend_mono1p") .allowlist_function("mono8_blend_mono4") - .allowlist_function("wnd565_fill") - .allowlist_function("wnd565_copy_rgb565") // fonts .allowlist_function("font_height") .allowlist_function("font_max_height") diff --git a/core/embed/rust/src/trezorhal/display.rs b/core/embed/rust/src/trezorhal/display.rs index 95a17350b..593b0572d 100644 --- a/core/embed/rust/src/trezorhal/display.rs +++ b/core/embed/rust/src/trezorhal/display.rs @@ -13,11 +13,11 @@ pub use ffi::{ #[cfg(all(feature = "framebuffer", not(feature = "framebuffer32bit")))] #[derive(Copy, Clone)] -pub struct FrameBuffer(*mut u16); +pub struct FrameBuffer(pub *mut u16); #[cfg(all(feature = "framebuffer", feature = "framebuffer32bit"))] #[derive(Copy, Clone)] -pub struct FrameBuffer(*mut u32); +pub struct FrameBuffer(pub *mut u32); pub fn backlight(val: i32) -> i32 { unsafe { ffi::display_backlight(val) } @@ -99,6 +99,7 @@ pub fn get_fb_addr() -> FrameBuffer { #[inline(always)] #[cfg(all(not(feature = "framebuffer"), feature = "disp_i8080_8bit_dw"))] pub fn pixeldata(c: u16) { + #[cfg(not(feature = "new_rendering"))] unsafe { ffi::DISPLAY_DATA_ADDRESS.write_volatile((c & 0xff) as u8); ffi::DISPLAY_DATA_ADDRESS.write_volatile((c >> 8) as u8); @@ -178,3 +179,8 @@ pub fn clear() { ffi::display_clear(); } } + +#[cfg(feature = "xframebuffer")] +pub fn get_frame_addr() -> *mut cty::c_void { + unsafe { ffi::display_get_frame_addr() } +} diff --git a/core/embed/rust/src/trezorhal/dma2d_new.rs b/core/embed/rust/src/trezorhal/dma2d_new.rs index 3c4e10f63..d2b39012b 100644 --- a/core/embed/rust/src/trezorhal/dma2d_new.rs +++ b/core/embed/rust/src/trezorhal/dma2d_new.rs @@ -142,7 +142,10 @@ impl Dma2d { } pub fn wait_for_transfer() { - unsafe { ffi::dma2d_wait_for_transfer() } + #[cfg(feature = "dma2d")] + unsafe { + ffi::dma2d_wait_for_transfer() + } } pub unsafe fn rgb565_fill(&self) { @@ -201,11 +204,13 @@ impl Dma2d { unsafe { ffi::mono8_blend_mono4(self) }; } - pub unsafe fn wnd565_fill(&self) { - unsafe { ffi::wnd565_fill(self) }; + #[cfg(feature = "new_rendering")] + pub unsafe fn display_fill(&self) { + unsafe { ffi::display_fill(self) }; } - pub unsafe fn wnd565_copy_rgb565(&self) { - unsafe { ffi::wnd565_copy_rgb565(self) }; + #[cfg(feature = "new_rendering")] + pub unsafe fn display_copy_rgb565(&self) { + unsafe { ffi::display_copy_rgb565(self) }; } } diff --git a/core/embed/rust/src/ui/shape/display/fake_display.rs b/core/embed/rust/src/ui/shape/display/fake_display.rs new file mode 100644 index 000000000..329a838c9 --- /dev/null +++ b/core/embed/rust/src/ui/shape/display/fake_display.rs @@ -0,0 +1,12 @@ +use crate::ui::{ + display::Color, + geometry::Rect, + shape::{DirectRenderer, Mono8Canvas}, +}; + +pub fn render_on_display<'a, F>(_clip: Option, _bg_color: Option, _func: F) +where + F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>), +{ + panic!("Not implemented") +} diff --git a/core/embed/rust/src/ui/shape/display/fb_mono8.rs b/core/embed/rust/src/ui/shape/display/fb_mono8.rs new file mode 100644 index 000000000..238fed5c6 --- /dev/null +++ b/core/embed/rust/src/ui/shape/display/fb_mono8.rs @@ -0,0 +1,45 @@ +use crate::ui::{ + display::Color, + geometry::{Offset, Rect}, + shape::{BasicCanvas, DirectRenderer, DrawingCache, Mono8Canvas, Viewport}, +}; + +use crate::trezorhal::display; + +use static_alloc::Bump; + +pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F) +where + F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>), +{ + static mut BUMP: Bump<[u8; 40 * 1024]> = Bump::uninit(); + + let bump = unsafe { &mut *core::ptr::addr_of_mut!(BUMP) }; + { + let width = display::DISPLAY_RESX as i16; + let height = display::DISPLAY_RESY as i16; + + bump.reset(); + + let cache = DrawingCache::new(bump, bump); + + let fb = unsafe { + core::slice::from_raw_parts_mut( + display::get_frame_addr() as *mut u8, + width as usize * height as usize * core::mem::size_of::(), + ) + }; + + let mut canvas = unwrap!(Mono8Canvas::new(Offset::new(width, height), None, fb)); + + if let Some(clip) = clip { + canvas.set_viewport(Viewport::new(clip)); + } + + let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache); + + func(&mut target); + + display::refresh(); + } +} diff --git a/core/embed/rust/src/ui/shape/display/fb_rgb565.rs b/core/embed/rust/src/ui/shape/display/fb_rgb565.rs new file mode 100644 index 000000000..986a10d75 --- /dev/null +++ b/core/embed/rust/src/ui/shape/display/fb_rgb565.rs @@ -0,0 +1,51 @@ +use crate::ui::{ + display::Color, + geometry::{Offset, Rect}, + shape::{BasicCanvas, DirectRenderer, DrawingCache, Rgb565Canvas, Viewport}, +}; + +use crate::trezorhal::display; + +use static_alloc::Bump; + +pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F) +where + F: FnOnce(&mut DirectRenderer<'_, 'a, Rgb565Canvas<'a>>), +{ + #[link_section = ".no_dma_buffers"] + static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit(); + + #[link_section = ".buf"] + static mut BUMP_B: Bump<[u8; 16 * 1024]> = Bump::uninit(); + + let bump_a = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_A) }; + let bump_b = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_B) }; + { + let width = display::DISPLAY_RESX as i16; + let height = display::DISPLAY_RESY as i16; + + bump_a.reset(); + bump_b.reset(); + + let cache = DrawingCache::new(bump_a, bump_b); + + let fb = unsafe { + core::slice::from_raw_parts_mut( + display::get_frame_addr() as *mut u8, + width as usize * height as usize * core::mem::size_of::(), + ) + }; + + let mut canvas = unwrap!(Rgb565Canvas::new(Offset::new(width, height), None, fb)); + + if let Some(clip) = clip { + canvas.set_viewport(Viewport::new(clip)); + } + + let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache); + + func(&mut target); + + display::refresh(); + } +} diff --git a/core/embed/rust/src/ui/shape/display/fb_rgba8888.rs b/core/embed/rust/src/ui/shape/display/fb_rgba8888.rs new file mode 100644 index 000000000..f731b403c --- /dev/null +++ b/core/embed/rust/src/ui/shape/display/fb_rgba8888.rs @@ -0,0 +1,51 @@ +use crate::ui::{ + display::Color, + geometry::{Offset, Rect}, + shape::{BasicCanvas, DirectRenderer, DrawingCache, Rgba8888Canvas, Viewport}, +}; + +use static_alloc::Bump; + +use crate::trezorhal::display; + +pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F) +where + F: FnOnce(&mut DirectRenderer<'_, 'a, Rgba8888Canvas<'a>>), +{ + #[link_section = ".no_dma_buffers"] + static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit(); + + #[link_section = ".buf"] + static mut BUMP_B: Bump<[u8; 16 * 1024]> = Bump::uninit(); + + let bump_a = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_A) }; + let bump_b = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_B) }; + { + let width = display::DISPLAY_RESX as i16; + let height = display::DISPLAY_RESY as i16; + + bump_a.reset(); + bump_b.reset(); + + let cache = DrawingCache::new(bump_a, bump_b); + + let fb = unsafe { + core::slice::from_raw_parts_mut( + display::get_frame_addr() as *mut u8, + width as usize * height as usize * core::mem::size_of::(), + ) + }; + + let mut canvas = unwrap!(Rgba8888Canvas::new(Offset::new(width, height), None, fb)); + + if let Some(clip) = clip { + canvas.set_viewport(Viewport::new(clip)); + } + + let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache); + + func(&mut target); + + display::refresh(); + } +} diff --git a/core/embed/rust/src/ui/shape/model/memory.md b/core/embed/rust/src/ui/shape/display/memory.md similarity index 100% rename from core/embed/rust/src/ui/shape/model/memory.md rename to core/embed/rust/src/ui/shape/display/memory.md diff --git a/core/embed/rust/src/ui/shape/display/mod.rs b/core/embed/rust/src/ui/shape/display/mod.rs new file mode 100644 index 000000000..c2f094d53 --- /dev/null +++ b/core/embed/rust/src/ui/shape/display/mod.rs @@ -0,0 +1,24 @@ +#[cfg(all(feature = "xframebuffer", feature = "display_mono"))] +pub mod fb_mono8; +#[cfg(all(feature = "xframebuffer", feature = "display_mono"))] +pub use fb_mono8::render_on_display; + +#[cfg(all(not(feature = "xframebuffer"), feature = "display_rgb565"))] +pub mod nofb_rgb565; +#[cfg(all(not(feature = "xframebuffer"), feature = "display_rgb565"))] +pub use nofb_rgb565::render_on_display; + +#[cfg(all(feature = "xframebuffer", feature = "display_rgb565"))] +pub mod fb_rgb565; +#[cfg(all(feature = "xframebuffer", feature = "display_rgb565"))] +pub use fb_rgb565::render_on_display; + +#[cfg(all(feature = "xframebuffer", feature = "display_rgba8888"))] +pub mod fb_rgba8888; +#[cfg(all(feature = "xframebuffer", feature = "display_rgba8888"))] +pub use fb_rgba8888::render_on_display; + +#[cfg(not(feature = "new_rendering"))] +pub mod fake_display; +#[cfg(not(feature = "new_rendering"))] +pub use fake_display::render_on_display; diff --git a/core/embed/rust/src/ui/shape/model/model_tt.rs b/core/embed/rust/src/ui/shape/display/nofb_rgb565.rs similarity index 88% rename from core/embed/rust/src/ui/shape/model/model_tt.rs rename to core/embed/rust/src/ui/shape/display/nofb_rgb565.rs index e92bd35af..b1ce7a947 100644 --- a/core/embed/rust/src/ui/shape/model/model_tt.rs +++ b/core/embed/rust/src/ui/shape/display/nofb_rgb565.rs @@ -13,7 +13,7 @@ use static_alloc::Bump; pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F) where - F: FnOnce(&mut ProgressiveRenderer<'_, 'a, Bump<[u8; 40 * 1024]>, DisplayModelT>), + F: FnOnce(&mut ProgressiveRenderer<'_, 'a, Bump<[u8; 40 * 1024]>, DisplayCanvas>), { #[link_section = ".no_dma_buffers"] static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit(); @@ -28,7 +28,7 @@ where bump_b.reset(); let cache = DrawingCache::new(bump_a, bump_b); - let mut canvas = DisplayModelT::acquire().unwrap(); + let mut canvas = DisplayCanvas::acquire().unwrap(); if let Some(clip) = clip { canvas.set_viewport(Viewport::new(clip)); @@ -42,12 +42,12 @@ where } } -pub struct DisplayModelT { +pub struct DisplayCanvas { size: Offset, viewport: Viewport, } -impl DisplayModelT { +impl DisplayCanvas { pub fn acquire() -> Option { let size = Offset::new(240, 240); // TODO let viewport = Viewport::from_size(size); @@ -55,7 +55,7 @@ impl DisplayModelT { } } -impl BasicCanvas for DisplayModelT { +impl BasicCanvas for DisplayCanvas { fn viewport(&self) -> Viewport { self.viewport } @@ -71,7 +71,7 @@ impl BasicCanvas for DisplayModelT { fn fill_rect(&mut self, r: Rect, color: Color, _alpha: u8) { let r = r.translate(self.viewport.origin); if let Some(dma2d) = Dma2d::new_fill(r, self.viewport.clip, color, 255) { - unsafe { dma2d.wnd565_fill() }; + unsafe { dma2d.display_fill() }; } } @@ -79,7 +79,7 @@ impl BasicCanvas for DisplayModelT { let r = r.translate(self.viewport.origin); if let Some(dma2d) = Dma2d::new_copy(r, self.viewport.clip, &bitmap) { match bitmap.format() { - BitmapFormat::RGB565 => unsafe { dma2d.wnd565_copy_rgb565() }, + BitmapFormat::RGB565 => unsafe { dma2d.display_copy_rgb565() }, _ => panic!("Unsupported DMA operation"), } bitmap.bitmap.mark_dma_pending(); diff --git a/core/embed/rust/src/ui/shape/mod.rs b/core/embed/rust/src/ui/shape/mod.rs index dbfe6a1ac..9fc9d7fe2 100644 --- a/core/embed/rust/src/ui/shape/mod.rs +++ b/core/embed/rust/src/ui/shape/mod.rs @@ -7,9 +7,9 @@ mod blur; mod cache; mod canvas; mod circle; +mod display; #[cfg(feature = "ui_jpeg_decoder")] mod jpeg; -mod model; mod qrcode; mod render; mod text; @@ -24,9 +24,9 @@ pub use blur::Blurring; pub use cache::drawing_cache::DrawingCache; pub use canvas::{BasicCanvas, Canvas, Mono8Canvas, Rgb565Canvas, Rgba8888Canvas, Viewport}; pub use circle::Circle; +pub use display::render_on_display; #[cfg(feature = "ui_jpeg_decoder")] pub use jpeg::JpegImage; -pub use model::render_on_display; pub use qrcode::QrImage; pub use render::{DirectRenderer, ProgressiveRenderer, Renderer}; pub use text::Text; diff --git a/core/embed/rust/src/ui/shape/model/mod.rs b/core/embed/rust/src/ui/shape/model/mod.rs deleted file mode 100644 index 7a041b13d..000000000 --- a/core/embed/rust/src/ui/shape/model/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -#[cfg(feature = "model_tr")] -pub mod model_tr; -#[cfg(feature = "model_tr")] -pub use model_tr::render_on_display; - -#[cfg(feature = "model_tt")] -pub mod model_tt; -#[cfg(feature = "model_tt")] -pub use model_tt::render_on_display; diff --git a/core/embed/rust/src/ui/shape/model/model_tr.rs b/core/embed/rust/src/ui/shape/model/model_tr.rs deleted file mode 100644 index 3da0bd95d..000000000 --- a/core/embed/rust/src/ui/shape/model/model_tr.rs +++ /dev/null @@ -1,57 +0,0 @@ -use crate::ui::{ - display, - display::Color, - geometry::{Offset, Rect}, - shape::{BasicCanvas, Canvas, DirectRenderer, DrawingCache, Mono8Canvas, Viewport}, -}; - -use static_alloc::Bump; - -pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F) -where - F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>), -{ - // TODO: do not use constants 128 & 64 directly - - static mut FRAME_BUFFER: [u8; 128 * 64] = [0u8; 128 * 64]; - - let fb = &mut unsafe { &mut *core::ptr::addr_of_mut!(FRAME_BUFFER) }[..]; - - static mut BUMP: Bump<[u8; 40 * 1024]> = Bump::uninit(); - - let bump = unsafe { &mut *core::ptr::addr_of_mut!(BUMP) }; - { - bump.reset(); - - let cache = DrawingCache::new(bump, bump); - let mut canvas = unwrap!(Mono8Canvas::new(Offset::new(128, 64), None, fb)); - - if let Some(clip) = clip { - canvas.set_viewport(Viewport::new(clip)); - } - - let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache); - - func(&mut target); - - refresh_display(&canvas); - } -} - -fn refresh_display(canvas: &Mono8Canvas) { - // TODO: optimize - - display::set_window(canvas.bounds()); - - let view = canvas.view(); - - for y in 0..canvas.size().y { - let row = unwrap!(view.row(y)); - for value in row.iter() { - let c = Color::rgb(*value, *value, *value); - display::pixeldata(c.into()); - } - } - - display::refresh(); -} diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h index 5e9ee471b..e4daafef9 100644 --- a/core/embed/rust/trezorhal.h +++ b/core/embed/rust/trezorhal.h @@ -1,13 +1,14 @@ #include TREZOR_BOARD -#include "../gdc/gdc.h" #include "buffers.h" #include "button.h" #include "common.h" #include "display.h" +#include "display_draw.h" #include "dma2d.h" #include "flash.h" #include "fonts/fonts.h" +#include "gl_dma2d.h" #include "haptic.h" #include "model.h" #include "rgb_led.h" diff --git a/core/embed/trezorhal/boards/stm32f429i-disc1.h b/core/embed/trezorhal/boards/stm32f429i-disc1.h index 9f8b0a65e..cd37a9712 100644 --- a/core/embed/trezorhal/boards/stm32f429i-disc1.h +++ b/core/embed/trezorhal/boards/stm32f429i-disc1.h @@ -3,18 +3,16 @@ #define HSE_8MHZ -#define MAX_DISPLAY_RESX 240 -#define MAX_DISPLAY_RESY 320 #define DISPLAY_RESX 240 #define DISPLAY_RESY 320 +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 +#define DISPLAY_LEGACY_HEADER "displays/ltdc.h" #define USE_I2C 1 #define USE_TOUCH 1 #define USE_SDRAM 1 #define USE_RGB_COLORS 1 -#include "displays/ltdc.h" - #define I2C_COUNT 1 #define I2C_INSTANCE_0 I2C3 #define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C3_CLK_ENABLE diff --git a/core/embed/trezorhal/boards/stm32u5a9j-dk.h b/core/embed/trezorhal/boards/stm32u5a9j-dk.h index 3ff3673ee..5b1ab241a 100644 --- a/core/embed/trezorhal/boards/stm32u5a9j-dk.h +++ b/core/embed/trezorhal/boards/stm32u5a9j-dk.h @@ -11,7 +11,10 @@ //#define USE_DISP_I8080_8BIT_DW 1 #define USE_HASH_PROCESSOR 1 -#include "displays/dsi.h" +#define DISPLAY_RESX 480 +#define DISPLAY_RESY 480 +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888 +#define DISPLAY_LEGACY_HEADER "displays/dsi.h" #define I2C_COUNT 1 #define I2C_INSTANCE_0 I2C5 diff --git a/core/embed/trezorhal/boards/trezor_1.h b/core/embed/trezorhal/boards/trezor_1.h index 4f126a720..7fec05ac7 100644 --- a/core/embed/trezorhal/boards/trezor_1.h +++ b/core/embed/trezorhal/boards/trezor_1.h @@ -5,7 +5,8 @@ #define USE_BUTTON 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 #define BTN_LEFT_PIN GPIO_PIN_5 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_r_v10.h b/core/embed/trezorhal/boards/trezor_r_v10.h index be44e5585..b48479d52 100644 --- a/core/embed/trezorhal/boards/trezor_r_v10.h +++ b/core/embed/trezorhal/boards/trezor_r_v10.h @@ -8,7 +8,9 @@ #define USE_I2C 1 #define USE_CONSUMPTION_MASK 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" #define BTN_LEFT_PIN GPIO_PIN_10 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_r_v3.h b/core/embed/trezorhal/boards/trezor_r_v3.h index 242a3f541..ffe8b6914 100644 --- a/core/embed/trezorhal/boards/trezor_r_v3.h +++ b/core/embed/trezorhal/boards/trezor_r_v3.h @@ -6,7 +6,9 @@ #define USE_BUTTON 1 #define USE_SBU 1 -#include "displays/ug-2828tswig01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 128 +#define DISPLAY_LEGACY_HEADER "displays/ug-2828tswig01.h" #define BTN_LEFT_PIN GPIO_PIN_0 #define BTN_LEFT_PORT GPIOA diff --git a/core/embed/trezorhal/boards/trezor_r_v4.h b/core/embed/trezorhal/boards/trezor_r_v4.h index 29054d200..9dbbb6267 100644 --- a/core/embed/trezorhal/boards/trezor_r_v4.h +++ b/core/embed/trezorhal/boards/trezor_r_v4.h @@ -6,7 +6,9 @@ #define USE_BUTTON 1 #define USE_SBU 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" #define BTN_LEFT_PIN GPIO_PIN_5 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_r_v6.h b/core/embed/trezorhal/boards/trezor_r_v6.h index 72a7cedea..d177c3d72 100644 --- a/core/embed/trezorhal/boards/trezor_r_v6.h +++ b/core/embed/trezorhal/boards/trezor_r_v6.h @@ -6,7 +6,9 @@ #define USE_BUTTON 1 #define USE_SBU 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" #define BTN_LEFT_PIN GPIO_PIN_10 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_t.h b/core/embed/trezorhal/boards/trezor_t.h index 557f8bb55..14e2ffd3f 100644 --- a/core/embed/trezorhal/boards/trezor_t.h +++ b/core/embed/trezorhal/boards/trezor_t.h @@ -3,9 +3,6 @@ #define HSE_8MHZ -#define DISPLAY_RESX 240 -#define DISPLAY_RESY 240 - #define USE_SD_CARD 1 #define USE_I2C 1 #define USE_TOUCH 1 @@ -14,12 +11,14 @@ #define USE_BACKLIGHT 1 #define USE_DISP_I8080_8BIT_DW 1 -#include "displays/panels/lx154a2422.h" -#include "displays/st7789v.h" +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 +#define DISPLAY_LEGACY_HEADER "displays/st7789v.h" + #define DISPLAY_IDENTIFY 1 #define DISPLAY_TE_PORT GPIOD #define DISPLAY_TE_PIN GPIO_PIN_12 -#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords #define BACKLIGHT_PWM_FREQ 10000 #define BACKLIGHT_PWM_TIM TIM1 diff --git a/core/embed/trezorhal/boards/trezor_t3t1_revE.h b/core/embed/trezorhal/boards/trezor_t3t1_revE.h index 4724aae75..3f9491bd9 100644 --- a/core/embed/trezorhal/boards/trezor_t3t1_revE.h +++ b/core/embed/trezorhal/boards/trezor_t3t1_revE.h @@ -1,9 +1,6 @@ #ifndef _TREZOR_T3T1_H #define _TREZOR_T3T1_H -#define DISPLAY_RESX 240 -#define DISPLAY_RESY 240 - #define VDD_1V8 1 #define HSE_16MHZ 1 @@ -17,8 +14,11 @@ #define USE_BACKLIGHT 1 #define USE_HASH_PROCESSOR 1 -#include "displays/panels/lx154a2422.h" -#include "displays/st7789v.h" +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define DISPLAY_LEGACY_HEADER "displays/st7789v.h" +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 + #define DISPLAY_IDENTIFY 1 #define DISPLAY_TE_PORT GPIOD #define DISPLAY_TE_PIN GPIO_PIN_12 @@ -27,10 +27,6 @@ #define DISPLAY_TE_INTERRUPT_GPIOSEL EXTI_GPIOD #define DISPLAY_TE_INTERRUPT_EXTI_LINE EXTI_LINE_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 TIM17 #define BACKLIGHT_PWM_TIM_CLK_EN __HAL_RCC_TIM17_CLK_ENABLE diff --git a/core/embed/trezorhal/boards/trezor_t3t1_v4.h b/core/embed/trezorhal/boards/trezor_t3t1_v4.h index fa5807b00..267dbabd4 100644 --- a/core/embed/trezorhal/boards/trezor_t3t1_v4.h +++ b/core/embed/trezorhal/boards/trezor_t3t1_v4.h @@ -1,9 +1,6 @@ #ifndef _TREZOR_T3T1_H #define _TREZOR_T3T1_H -#define DISPLAY_RESX 240 -#define DISPLAY_RESY 240 - #define VDD_1V8 1 #define HSE_16MHZ 1 @@ -17,8 +14,11 @@ #define USE_BACKLIGHT 1 #define USE_HASH_PROCESSOR 1 -#include "displays/panels/lx154a2422.h" -#include "displays/st7789v.h" +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define DISPLAY_LEGACY_HEADER "displays/st7789v.h" +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 + #define DISPLAY_IDENTIFY 1 #define DISPLAY_TE_PORT GPIOD #define DISPLAY_TE_PIN GPIO_PIN_12 @@ -27,10 +27,6 @@ #define DISPLAY_TE_INTERRUPT_GPIOSEL EXTI_GPIOD #define DISPLAY_TE_INTERRUPT_EXTI_LINE EXTI_LINE_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 diff --git a/core/embed/trezorhal/display.h b/core/embed/trezorhal/display.h index 4cc2a2bc1..1b3f72b0f 100644 --- a/core/embed/trezorhal/display.h +++ b/core/embed/trezorhal/display.h @@ -20,11 +20,19 @@ #ifndef TREZORHAL_DISPLAY_H #define TREZORHAL_DISPLAY_H +#if NEW_RENDERING +#include +#else + #include #include "common.h" #include "display_draw.h" #include TREZOR_BOARD +#ifdef DISPLAY_LEGACY_HEADER +#include DISPLAY_LEGACY_HEADER +#endif + #ifndef DISPLAY_FRAMEBUFFER_OFFSET_Y #define DISPLAY_FRAMEBUFFER_OFFSET_Y 0 #endif @@ -69,4 +77,5 @@ uint8_t *display_get_wr_addr(void); void display_shift_window(uint16_t pixels); uint16_t display_get_window_offset(void); +#endif // NEW_RENDERING #endif // TREZORHAL_DISPLAY_H diff --git a/core/embed/trezorhal/dma2d.h b/core/embed/trezorhal/dma2d.h index 20019cf4e..b389a9ff0 100644 --- a/core/embed/trezorhal/dma2d.h +++ b/core/embed/trezorhal/dma2d.h @@ -20,10 +20,12 @@ #ifndef TREZORHAL_DMA2D_H #define TREZORHAL_DMA2D_H -#include "../gdc/gdc_core.h" - +#include +#include #include "common.h" +#include "gl_dma2d.h" + void dma2d_init(void); void dma2d_setup_const(void); diff --git a/core/embed/trezorhal/stm32f4/common.c b/core/embed/trezorhal/stm32f4/common.c index 23f9b8202..62e08db27 100644 --- a/core/embed/trezorhal/stm32f4/common.c +++ b/core/embed/trezorhal/stm32f4/common.c @@ -224,7 +224,11 @@ void collect_hw_entropy(void) { void ensure_compatible_settings(void) { display_finish_actions(); #ifdef TREZOR_MODEL_T +#ifdef NEW_RENDERING + display_set_compatible_settings(); +#else display_set_big_endian(); +#endif display_orientation(0); set_core_clock(CLOCK_168_MHZ); backlight_pwm_set_slow(); diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_driver.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_driver.c new file mode 100644 index 000000000..e8f0007cc --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_driver.c @@ -0,0 +1,194 @@ +/* + * 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 "display_fb.h" +#include "display_io.h" +#include "display_panel.h" + +#include "backlight_pwm.h" + +#include "supervise.h" + +#ifndef BOARDLOADER +#include "bg_copy.h" +#endif + +#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240) +#error "Incompatible display resolution" +#endif + +// Display driver context. +typedef struct { + // Current display orientation (0, 90, 180, 270) + int orientation_angle; +} display_driver_t; + +// Display driver instance +static display_driver_t g_display_driver; + +void display_init(void) { + display_driver_t* drv = &g_display_driver; + memset(drv, 0, sizeof(display_driver_t)); + + display_io_init_gpio(); + display_io_init_fmc(); + display_panel_init(); + display_panel_set_little_endian(); + backlight_pwm_init(); + +#ifdef XFRAMEBUFFER + display_io_init_te_interrupt(); +#endif +} + +void display_reinit(void) { + display_driver_t* drv = &g_display_driver; + memset(drv, 0, sizeof(display_driver_t)); + + // Reinitialize FMC to set correct timing + // We have to do this in reinit because boardloader is fixed. + display_io_init_fmc(); + + // Important for model T as this is not set in boardloader + display_panel_set_little_endian(); + display_panel_init_gamma(); + backlight_pwm_reinit(); + +#ifdef XFRAMEBUFFER + display_io_init_te_interrupt(); +#endif +} + +void display_finish_actions(void) { + // !@# disable interrupt + // !@# wait for dma ops +} + +int display_set_backlight(int level) { +#ifdef XFRAMEBUFFER +#ifndef BOARDLOADER + // wait for DMA transfer to finish before changing backlight + // so that we know that panel has current data + if (backlight_pwm_get() != level && !is_mode_handler()) { + bg_copy_wait(); + } +#endif +#endif + + return backlight_pwm_set(level); +} + +int display_get_backlight(void) { return backlight_pwm_get(); } + +int display_set_orientation(int angle) { + display_driver_t* drv = &g_display_driver; + + if (angle != drv->orientation_angle) { + if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { + drv->orientation_angle = angle; + +#ifdef XFRAMEBUFFER + memset(physical_frame_buffer_0, 0, sizeof(physical_frame_buffer_0)); + memset(physical_frame_buffer_1, 0, sizeof(physical_frame_buffer_1)); +#endif + + display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { + // 2 bytes per pixel because we're using RGB 5-6-5 format + ISSUE_PIXEL_DATA(0x0000); + } + + display_panel_rotate(angle); + } + } + + return drv->orientation_angle; +} + +int display_get_orientation(void) { + display_driver_t* drv = &g_display_driver; + + return drv->orientation_angle; +} + +#ifndef XFRAMEBUFFER +void display_refresh(void) { + // if the framebuffer is not used the implementation is empty +} +#endif + +void display_wait_for_sync(void) { +#ifdef DISPLAY_TE_PIN + uint32_t id = display_panel_identify(); + if (id && (id != DISPLAY_ID_GC9307)) { + // synchronize with the panel synchronization signal + // in order to avoid visual tearing effects + while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) + ; + while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) + ; + } +#endif +} + +const char* display_save(const char* prefix) { return NULL; } + +void display_clear_save(void) {} + +void display_set_compatible_settings(void) { display_panel_set_big_endian(); } + +static inline void set_window(const dma2d_params_t* dp) { + display_panel_set_window(dp->dst_x, dp->dst_y, dp->dst_x + dp->width - 1, + dp->dst_y + dp->height + 1); +} + +// Fills a rectangle with a specified color +void display_fill(const dma2d_params_t* dp) { + set_window(dp); + + uint16_t height = dp->height; + + while (height-- > 0) { + for (int x = 0; x < dp->width; x++) { + ISSUE_PIXEL_DATA(dp->src_fg); + } + } +} + +// Copies an RGB565 bitmap to specified rectangle +void display_copy_rgb565(const dma2d_params_t* dp) { + set_window(dp); + + uint16_t* src_ptr = (uint16_t*)dp->src_row + dp->src_x; + uint16_t height = dp->height; + + while (height-- > 0) { + for (int x = 0; x < dp->width; x++) { + ISSUE_PIXEL_DATA(src_ptr[x]); + } + src_ptr += dp->src_stride / sizeof(*src_ptr); + } +} + +// Copies a MONO4 bitmap to specified rectangle +// void display_copy_mono4(gdc_dma2d_t *dp); diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.c new file mode 100644 index 000000000..1e701b0fe --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.c @@ -0,0 +1,160 @@ +/* + * 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 TREZOR_BOARD +#include STM32_HAL_H + +#include "display_fb.h" +#include "display_io.h" +#include "display_panel.h" + +#include "irq.h" +#include "supervise.h" + +#ifndef BOARDLOADER +#include "bg_copy.h" +#endif + +#ifdef XFRAMEBUFFER + +#ifndef STM32U5 +#error Framebuffer only supported on STM32U5 for now +#endif + +// Physical frame buffers in internal SRAM memory +__attribute__((section(".fb1"))) +ALIGN_32BYTES(uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]); + +__attribute__((section(".fb2"))) +ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]); + +// The current frame buffer selector at fixed memory address +// It's shared between bootloaders and the firmware +__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer = + 0; + +static bool pending_fb_switch = false; + +#ifndef BOARDLOADER +void DISPLAY_TE_INTERRUPT_HANDLER(void) { + HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); + + if (current_frame_buffer == 1) { + bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_1, + (uint8_t *)DISPLAY_DATA_ADDRESS, + DISPLAY_RESX * DISPLAY_RESY * 2); + + } else { + bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_0, + (uint8_t *)DISPLAY_DATA_ADDRESS, + DISPLAY_RESX * DISPLAY_RESY * 2); + } + + pending_fb_switch = false; + __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); +} + +static void wait_for_fb_switch(void) { + while (pending_fb_switch) { + __WFI(); + } + bg_copy_wait(); +} +#endif + +static void copy_fb_to_display(uint16_t *fb) { + for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { + // 2 bytes per pixel because we're using RGB 5-6-5 format + ISSUE_PIXEL_DATA(fb[i]); + } +} + +static void switch_fb_manually(void) { + // sync with the panel refresh + while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) { + } + while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) { + } + + if (current_frame_buffer == 0) { + current_frame_buffer = 1; + copy_fb_to_display((uint16_t *)physical_frame_buffer_1); + memcpy(physical_frame_buffer_0, physical_frame_buffer_1, + sizeof(physical_frame_buffer_0)); + + } else { + current_frame_buffer = 0; + copy_fb_to_display((uint16_t *)physical_frame_buffer_0); + memcpy(physical_frame_buffer_1, physical_frame_buffer_0, + sizeof(physical_frame_buffer_1)); + } +} + +#ifndef BOARDLOADER +static void switch_fb_in_backround(void) { + if (current_frame_buffer == 0) { + current_frame_buffer = 1; + + memcpy(physical_frame_buffer_0, physical_frame_buffer_1, + sizeof(physical_frame_buffer_0)); + + pending_fb_switch = true; + __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); + svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + } else { + current_frame_buffer = 0; + memcpy(physical_frame_buffer_1, physical_frame_buffer_0, + sizeof(physical_frame_buffer_1)); + + pending_fb_switch = true; + __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); + svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + } +} +#endif + +void *display_get_frame_addr(void) { + if (current_frame_buffer == 0) { + return (void *)physical_frame_buffer_1; + } else { + return (void *)physical_frame_buffer_0; + } +} + +void display_refresh(void) { +#ifndef BOARDLOADER + wait_for_fb_switch(); + display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + + if (is_mode_handler()) { + switch_fb_manually(); + } else { + switch_fb_in_backround(); + } +#else + display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + switch_fb_manually(); +#endif +} + +#endif // XFRAMEBUFFER diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.h b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.h new file mode 100644 index 000000000..bad36e107 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.h @@ -0,0 +1,46 @@ +/* + * 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_DISPLAY_INTERNAL_H +#define TREZOR_HAL_DISPLAY_INTERNAL_H + +#include TREZOR_BOARD + +#include + +#ifdef XFRAMEBUFFER + +// Size of the physical frame buffer in bytes +#define PHYSICAL_FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2) + +// Physical frame buffers in internal SRAM memory +// +// Both frame buffers layes in the fixed addresses that +// are shared between bootloaders and the firmware. +extern uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]; +extern uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]; + +// The current frame buffer selector at fixed memory address +// +// The variable address is shared between bootloaders and the firmware +extern uint32_t current_frame_buffer; + +#endif // XFRAMEBUFFER + +#endif // TREZOR_HAL_DISPLAY_INTERNAL_H diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_io.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.c new file mode 100644 index 000000000..fe02ca207 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.c @@ -0,0 +1,145 @@ +/* + * 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 TREZOR_BOARD +#include STM32_HAL_H + +#include "display_io.h" +#include "irq.h" + +__IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS = + (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE); +__IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS = + (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE | + (DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN)); + +void display_io_init_gpio(void) { + // init peripherals + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_FMC_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStructure; + + // LCD_RST/PC14 + 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_14; + // default to keeping display in reset + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + +#ifdef DISPLAY_TE_PIN + // LCD_FMARK (tearing effect) + GPIO_InitStructure.Mode = GPIO_MODE_INPUT; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = 0; + GPIO_InitStructure.Pin = DISPLAY_TE_PIN; + HAL_GPIO_Init(DISPLAY_TE_PORT, &GPIO_InitStructure); +#endif + + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = GPIO_AF12_FMC; + // LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5 + GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + // LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1 + GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + // LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10 + GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOE, &GPIO_InitStructure); +#ifdef USE_DISP_I8080_16BIT_DW + // LCD_D8/PE11 LCD_D9/PE12 LCD_D10/PE13 LCD_D11/PE14 + GPIO_InitStructure.Pin = + GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14; + HAL_GPIO_Init(GPIOE, &GPIO_InitStructure); + // LCD_D12/PE15 + GPIO_InitStructure.Pin = GPIO_PIN_15; + HAL_GPIO_Init(GPIOE, &GPIO_InitStructure); + // LCD_D13/PD8 LCD_D14/PD9 LCD_D15/PD10 + GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); +#endif +} + +void display_io_init_fmc(void) { + // Reference UM1725 "Description of STM32F4 HAL and LL drivers", + // section 64.2.1 "How to use this driver" + SRAM_HandleTypeDef external_display_data_sram = {0}; + external_display_data_sram.Instance = FMC_NORSRAM_DEVICE; + external_display_data_sram.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1; + external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; +#ifdef USE_DISP_I8080_16BIT_DW + external_display_data_sram.Init.MemoryDataWidth = + FMC_NORSRAM_MEM_BUS_WIDTH_16; +#elif USE_DISP_I8080_8BIT_DW + external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8; +#endif + external_display_data_sram.Init.BurstAccessMode = + FMC_BURST_ACCESS_MODE_DISABLE; + external_display_data_sram.Init.WaitSignalPolarity = + FMC_WAIT_SIGNAL_POLARITY_LOW; + 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; + external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + external_display_data_sram.Init.AsynchronousWait = + FMC_ASYNCHRONOUS_WAIT_DISABLE; + external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; + external_display_data_sram.Init.ContinuousClock = + FMC_CONTINUOUS_CLOCK_SYNC_ONLY; + external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE; + + // reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6 + FMC_NORSRAM_TimingTypeDef normal_mode_timing = {0}; + normal_mode_timing.AddressSetupTime = 5; + normal_mode_timing.AddressHoldTime = 1; // don't care + normal_mode_timing.DataSetupTime = 6; + normal_mode_timing.BusTurnAroundDuration = 0; // don't care + normal_mode_timing.CLKDivision = 2; // don't care + normal_mode_timing.DataLatency = 2; // don't care + normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A; + + HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL); +} + +#ifdef DISPLAY_TE_INTERRUPT_HANDLER +void display_io_init_te_interrupt(void) { + EXTI_HandleTypeDef EXTI_Handle = {0}; + EXTI_ConfigTypeDef EXTI_Config = {0}; + EXTI_Config.GPIOSel = DISPLAY_TE_INTERRUPT_GPIOSEL; + EXTI_Config.Line = DISPLAY_TE_INTERRUPT_EXTI_LINE; + EXTI_Config.Mode = EXTI_MODE_INTERRUPT; + EXTI_Config.Trigger = EXTI_TRIGGER_RISING; + HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config); + + // setup interrupt for tearing effect pin + HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0); +} +#endif diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_io.h b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.h new file mode 100644 index 000000000..811151159 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.h @@ -0,0 +1,67 @@ +/* + * 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_DISPLAY_IO_H +#define TREZORHAL_DISPLAY_IO_H + +#include STM32_HAL_H +#include TREZOR_BOARD + +void display_io_init_gpio(void); +void display_io_init_fmc(void); +void display_io_init_te_interrupt(void); + +#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 +#define DISP_MEM_TYPE uint16_t +#elif USE_DISP_I8080_8BIT_DW +#define DISPLAY_ADDR_SHIFT 1 +#define DISP_MEM_TYPE uint8_t +#else +#error "Unsupported display interface" +#endif + +/*#define DISPLAY_CMD_ADDRESS ((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE)) +#define DISPLAY_DATA_ADDRESS \ + ((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE | \ + (DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN))) +*/ + +extern __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS; +extern __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS; + +#define ISSUE_CMD_BYTE(X) (*(DISPLAY_CMD_ADDRESS) = (X)) +#define ISSUE_DATA_BYTE(X) (*(DISPLAY_DATA_ADDRESS) = (X)) + +#ifdef USE_DISP_I8080_16BIT_DW +#define ISSUE_PIXEL_DATA(X) DATA(X) +#elif USE_DISP_I8080_8BIT_DW +#define ISSUE_PIXEL_DATA(X) \ + ISSUE_DATA_BYTE((X)&0xFF); \ + ISSUE_DATA_BYTE((X) >> 8) +#endif + +#endif // TREZORHAL_DISPLAY_IO_H \ No newline at end of file diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.c new file mode 100644 index 000000000..001579b87 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.c @@ -0,0 +1,235 @@ +/* + * 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 . + */ + +// using const volatile instead of #define results in binaries that change +// only in 1-byte when the flag changes. +// using #define leads compiler to over-optimize the code leading to bigger +// differencies in the resulting binaries. + +#include "display_panel.h" +#include "display_io.h" + +#ifdef TREZOR_MODEL_T +#include "panels/154a.h" +#include "panels/lx154a2411.h" +#include "panels/lx154a2422.h" +#include "panels/tf15411a.h" +#else +#include "panels/lx154a2422.h" +#endif + +// using const volatile instead of #define results in binaries that change +// only in 1-byte when the flag changes. +// using #define leads compiler to over-optimize the code leading to bigger +// differencies in the resulting binaries. +const volatile uint8_t DISPLAY_ST7789V_INVERT_COLORS2 = 1; + +#ifdef DISPLAY_IDENTIFY +static uint32_t read_display_id(uint8_t command) { + volatile uint8_t c = 0; + uint32_t id = 0; + ISSUE_CMD_BYTE(command); + c = *DISPLAY_DATA_ADDRESS; // first returned value is a dummy value and + // should be discarded + c = *DISPLAY_DATA_ADDRESS; + id |= (c << 16); + c = *DISPLAY_DATA_ADDRESS; + id |= (c << 8); + c = *DISPLAY_DATA_ADDRESS; + id |= c; + return id; +} + +uint32_t display_panel_identify(void) { + static uint32_t id = 0x000000U; + static bool id_initialized = false; + + // Return immediately if id has been already initialized + if (id_initialized) return id; + + // RDDID: Read Display ID + id = read_display_id(0x04); + // the default RDDID for ILI9341 should be 0x8000. + // some display modules return 0x0. + // the ILI9341 has an extra id, let's check it here. + if ((id != DISPLAY_ID_ST7789V) && (id != DISPLAY_ID_GC9307)) { + // Read ID4 + uint32_t id4 = read_display_id(0xD3); + if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341 + id = id4; + } + } + id_initialized = true; + return id; +} +#else +uint32_t display_panbel_identify(void) { return DISPLAY_ID_ST7789V; } +#endif + +bool display_panel_is_inverted() { + bool inv_on = false; + uint32_t id = display_panel_identify(); + if (id == DISPLAY_ID_ST7789V) { + volatile uint8_t c = 0; + ISSUE_CMD_BYTE(0x09); // read display status + c = *DISPLAY_DATA_ADDRESS; // don't care + c = *DISPLAY_DATA_ADDRESS; // don't care + c = *DISPLAY_DATA_ADDRESS; // don't care + c = *DISPLAY_DATA_ADDRESS; + if (c & 0x20) { + inv_on = true; + } + c = *DISPLAY_DATA_ADDRESS; // don't care + } + + return inv_on; +} + +void display_panel_sleep(void) { + uint32_t id = display_panel_identify(); + if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || + (id == DISPLAY_ID_ST7789V)) { + ISSUE_CMD_BYTE(0x28); // DISPOFF: Display Off + ISSUE_CMD_BYTE(0x10); // SLPIN: Sleep in + HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before + // sending any new commands + } +} + +void display_panel_unsleep(void) { + uint32_t id = display_panel_identify(); + if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || + (id == DISPLAY_ID_ST7789V)) { + ISSUE_CMD_BYTE(0x11); // SLPOUT: Sleep Out + HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before + // sending any new commands + ISSUE_CMD_BYTE(0x29); // DISPON: Display On + } +} + +void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1, + uint16_t y1) { + uint32_t id = display_panel_identify(); + if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) || + (id == DISPLAY_ID_ST7789V)) { + ISSUE_CMD_BYTE(0x2A); + ISSUE_DATA_BYTE(x0 >> 8); + ISSUE_DATA_BYTE(x0 & 0xFF); + ISSUE_DATA_BYTE(x1 >> 8); + ISSUE_DATA_BYTE(x1 & 0xFF); // column addr set + ISSUE_CMD_BYTE(0x2B); + ISSUE_DATA_BYTE(y0 >> 8); + ISSUE_DATA_BYTE(y0 & 0xFF); + ISSUE_DATA_BYTE(y1 >> 8); + ISSUE_DATA_BYTE(y1 & 0xFF); // row addr set + ISSUE_CMD_BYTE(0x2C); + } +} + +void display_panel_set_little_endian(void) { + uint32_t id = display_panel_identify(); + if (id == DISPLAY_ID_GC9307) { + // CANNOT SET ENDIAN FOR GC9307 + } else if (id == DISPLAY_ID_ST7789V) { + ISSUE_CMD_BYTE(0xB0); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0xF8); + } else if (id == DISPLAY_ID_ILI9341V) { + // Interface Control: XOR BGR as ST7789V does + ISSUE_CMD_BYTE(0xF6); + ISSUE_DATA_BYTE(0x09); + ISSUE_DATA_BYTE(0x30); + ISSUE_DATA_BYTE(0x20); + } +} + +void display_panel_set_big_endian(void) { + uint32_t id = display_panel_identify(); + if (id == DISPLAY_ID_GC9307) { + // CANNOT SET ENDIAN FOR GC9307 + } else if (id == DISPLAY_ID_ST7789V) { + ISSUE_CMD_BYTE(0xB0); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0xF0); + } else if (id == DISPLAY_ID_ILI9341V) { + // Interface Control: XOR BGR as ST7789V does + ISSUE_CMD_BYTE(0xF6); + ISSUE_DATA_BYTE(0x09); + ISSUE_DATA_BYTE(0x30); + ISSUE_DATA_BYTE(0x00); + } +} + +void display_panal_init(void) { + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14 + // wait 10 milliseconds. only needs to be low for 10 microseconds. + // my dev display module ties display reset and touch panel reset together. + // keeping this low for max(display_reset_time, ctpm_reset_time) aids + // development and does not hurt. + HAL_Delay(10); + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); // LCD_RST/PC14 + // max wait time for hardware reset is 120 milliseconds + // (experienced display flakiness using only 5ms wait before sending commands) + HAL_Delay(120); + + // identify the controller we will communicate with +#ifdef TREZOR_MODEL_T + uint32_t id = display_panel_identify(); + if (id == DISPLAY_ID_GC9307) { + tf15411a_init_seq(); + } else if (id == DISPLAY_ID_ST7789V) { + if (DISPLAY_ST7789V_INVERT_COLORS2) { + lx154a2422_init_seq(); + } else { + lx154a2411_init_seq(); + } + } else if (id == DISPLAY_ID_ILI9341V) { + _154a_init_seq(); + } +#else + lx154a2422_init_seq(); +#endif + + display_panel_unsleep(); +} + +void display_panel_init_gamma(void) { +#ifdef TREZOR_MODEL_T + uint32_t id = display_panel_identify(); + if (id == DISPLAY_ID_ST7789V && display_panel_is_inverted()) { + // newest TT display - set proper gamma + lx154a2422_gamma(); + } else if (id == DISPLAY_ID_ST7789V) { + lx154a2411_gamma(); + } +#endif +} + +void display_panel_rotate(int angle) { +#ifdef TREZOR_MODEL_T + uint32_t id = display_panel_identify(); + if (id == DISPLAY_ID_GC9307) { + tf15411a_rotate(angle); + } else { + lx154a2422_rotate(angle); + } +#else + lx154a2422_rotate(angle); +#endif +} diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.h b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.h new file mode 100644 index 000000000..8e63577c0 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.h @@ -0,0 +1,52 @@ +/* + * 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_ST7789_PANEL_H +#define TREZORHAL_ST7789_PANEL_H + +#include +#include + +// section "9.1.3 RDDID (04h): Read Display ID" +// of ST7789V datasheet +#define DISPLAY_ID_ST7789V 0x858552U +// section "6.2.1. Read display identification information (04h)" +// of GC9307 datasheet +#define DISPLAY_ID_GC9307 0x009307U +// section "8.3.23 Read ID4 (D3h)" +// of ILI9341V datasheet +#define DISPLAY_ID_ILI9341V 0x009341U + +// Identifies the connected display panel and +// returns one of DISPLAY_ID_xxx constant +uint32_t display_panel_identify(void); +bool display_panel_is_inverted(); + +void display_panel_init(void); +void display_panel_init_gamma(void); +void display_panel_set_little_endian(void); +void display_panel_set_big_endian(void); + +void display_panel_sleep(void); +void display_panel_unsleep(void); +void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1, + uint16_t y1); +void display_panel_rotate(int angle); + +#endif // TREZORHAL_ST7789_PANEL_H \ No newline at end of file diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.c new file mode 100644 index 000000000..8d7dc0fe9 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.c @@ -0,0 +1,132 @@ +/* + * 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 "../display_io.h" + +void _154a_init_seq(void) { + // most recent manual: https://www.newhavendisplay.com/app_notes/ILI9341.pdf + // TEON: Tearing Effect Line On; V-blanking only + ISSUE_CMD_BYTE(0x35); + ISSUE_DATA_BYTE(0x00); + + // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits + // input) + ISSUE_CMD_BYTE(0x3A); + ISSUE_DATA_BYTE(0x55); + + // Display Function Control: gate scan direction 319 -> 0 + ISSUE_CMD_BYTE(0xB6); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0xC2); + ISSUE_DATA_BYTE(0x27); + ISSUE_DATA_BYTE(0x00); + + // Interface Control: XOR BGR as ST7789V does + ISSUE_CMD_BYTE(0xF6); + ISSUE_DATA_BYTE(0x09); + ISSUE_DATA_BYTE(0x30); + ISSUE_DATA_BYTE(0x00); + + // the above config is the most important and definitely necessary + + ISSUE_CMD_BYTE(0xCF); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0xC1); + ISSUE_DATA_BYTE(0x30); + + ISSUE_CMD_BYTE(0xED); + ISSUE_DATA_BYTE(0x64); + ISSUE_DATA_BYTE(0x03); + ISSUE_DATA_BYTE(0x12); + ISSUE_DATA_BYTE(0x81); + + ISSUE_CMD_BYTE(0xE8); + ISSUE_DATA_BYTE(0x85); + ISSUE_DATA_BYTE(0x10); + ISSUE_DATA_BYTE(0x7A); + + ISSUE_CMD_BYTE(0xF7); + ISSUE_DATA_BYTE(0x20); + + ISSUE_CMD_BYTE(0xEA); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0x00); + + // power control VRH[5:0] + ISSUE_CMD_BYTE(0xC0); + ISSUE_DATA_BYTE(0x23); + + // power control SAP[2:0] BT[3:0] + ISSUE_CMD_BYTE(0xC1); + ISSUE_DATA_BYTE(0x12); + + // vcm control 1 + ISSUE_CMD_BYTE(0xC5); + ISSUE_DATA_BYTE(0x60); + ISSUE_DATA_BYTE(0x44); + + // vcm control 2 + ISSUE_CMD_BYTE(0xC7); + ISSUE_DATA_BYTE(0x8A); + + // framerate + ISSUE_CMD_BYTE(0xB1); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0x18); + + // 3 gamma func disable + ISSUE_CMD_BYTE(0xF2); + ISSUE_DATA_BYTE(0x00); + + // gamma curve 1 + ISSUE_CMD_BYTE(0xE0); + ISSUE_DATA_BYTE(0x0F); + ISSUE_DATA_BYTE(0x2F); + ISSUE_DATA_BYTE(0x2C); + ISSUE_DATA_BYTE(0x0B); + ISSUE_DATA_BYTE(0x0F); + ISSUE_DATA_BYTE(0x09); + ISSUE_DATA_BYTE(0x56); + ISSUE_DATA_BYTE(0xD9); + ISSUE_DATA_BYTE(0x4A); + ISSUE_DATA_BYTE(0x0B); + ISSUE_DATA_BYTE(0x14); + ISSUE_DATA_BYTE(0x05); + ISSUE_DATA_BYTE(0x0C); + ISSUE_DATA_BYTE(0x06); + ISSUE_DATA_BYTE(0x00); + + // gamma curve 2 + ISSUE_CMD_BYTE(0xE1); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0x10); + ISSUE_DATA_BYTE(0x13); + ISSUE_DATA_BYTE(0x04); + ISSUE_DATA_BYTE(0x10); + ISSUE_DATA_BYTE(0x06); + ISSUE_DATA_BYTE(0x25); + ISSUE_DATA_BYTE(0x26); + ISSUE_DATA_BYTE(0x3B); + ISSUE_DATA_BYTE(0x04); + ISSUE_DATA_BYTE(0x0B); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x33); + ISSUE_DATA_BYTE(0x39); + ISSUE_DATA_BYTE(0x0F); +} diff --git a/core/embed/gdc/gdc.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.h similarity index 80% rename from core/embed/gdc/gdc.h rename to core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.h index 20f67638c..410455abb 100644 --- a/core/embed/gdc/gdc.h +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.h @@ -17,14 +17,11 @@ * along with this program. If not, see . */ -#ifndef GDC_H -#define GDC_H +#ifndef _154A_H_ +#define _154A_H_ -#include "gdc_bitmap.h" -#include "gdc_color.h" -#include "gdc_core.h" -#include "gdc_geom.h" -#include "gdc_ops.h" -#include "gdc_text.h" +// ILI9341 IC controller -#endif // GDC_H +void _154a_init_seq(void); + +#endif diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c new file mode 100644 index 000000000..b81ee75bb --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c @@ -0,0 +1,82 @@ + +#include "../display_io.h" + +void lx154a2411_gamma(void) { + // positive voltage correction + ISSUE_CMD_BYTE(0xE0); + ISSUE_DATA_BYTE(0xD0); + ISSUE_DATA_BYTE(0x03); + ISSUE_DATA_BYTE(0x08); + ISSUE_DATA_BYTE(0x0E); + ISSUE_DATA_BYTE(0x11); + ISSUE_DATA_BYTE(0x2B); + ISSUE_DATA_BYTE(0x3B); + ISSUE_DATA_BYTE(0x44); + ISSUE_DATA_BYTE(0x4C); + ISSUE_DATA_BYTE(0x2B); + ISSUE_DATA_BYTE(0x16); + ISSUE_DATA_BYTE(0x15); + ISSUE_DATA_BYTE(0x1E); + ISSUE_DATA_BYTE(0x21); + + // negative voltage correction + ISSUE_CMD_BYTE(0xE1); + ISSUE_DATA_BYTE(0xD0); + ISSUE_DATA_BYTE(0x03); + ISSUE_DATA_BYTE(0x08); + ISSUE_DATA_BYTE(0x0E); + ISSUE_DATA_BYTE(0x11); + ISSUE_DATA_BYTE(0x2B); + ISSUE_DATA_BYTE(0x3B); + ISSUE_DATA_BYTE(0x54); + ISSUE_DATA_BYTE(0x4C); + ISSUE_DATA_BYTE(0x2B); + ISSUE_DATA_BYTE(0x16); + ISSUE_DATA_BYTE(0x15); + ISSUE_DATA_BYTE(0x1E); + ISSUE_DATA_BYTE(0x21); +} + +void lx154a2411_init_seq(void) { + // most recent manual: + // https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf + // TEON: Tearing Effect Line On; V-blanking only + ISSUE_CMD_BYTE(0x35); + ISSUE_DATA_BYTE(0x00); + + // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits + // input) + ISSUE_CMD_BYTE(0x3A); + ISSUE_DATA_BYTE(0x55); + + // CMD2EN: Commands in command table 2 can be executed when EXTC level is Low + ISSUE_CMD_BYTE(0xDF); + ISSUE_DATA_BYTE(0x5A); + ISSUE_DATA_BYTE(0x69); + ISSUE_DATA_BYTE(0x02); + ISSUE_DATA_BYTE(0x01); + + // LCMCTRL: LCM Control: XOR RGB setting + ISSUE_CMD_BYTE(0xC0); + ISSUE_DATA_BYTE(0x20); + + // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.; + // gate scan direction 319 -> 0 + ISSUE_CMD_BYTE(0xE4); + ISSUE_DATA_BYTE(0x1D); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x11); + + // INVOFF (20h): Display Inversion Off + // INVON (21h): Display Inversion On + ISSUE_CMD_BYTE(0x20); + + // the above config is the most important and definitely necessary + + // PWCTRL1: Power Control 1 + ISSUE_CMD_BYTE(0xD0); + ISSUE_DATA_BYTE(0xA4); + ISSUE_DATA_BYTE(0xA1); + + lx154a2411_gamma(); +} diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.h new file mode 100644 index 000000000..347aa3b58 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.h @@ -0,0 +1,27 @@ +/* + * 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 LX154A2411_H_ +#define LX154A2411_H_ + +// ST7789_V IC controller +void lx154a2411_gamma(void); +void lx154a2411_init_seq(void); + +#endif diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c new file mode 100644 index 000000000..37d96660a --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c @@ -0,0 +1,150 @@ +/* + * 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 "../display_io.h" +#include "touch.h" + +void lx154a2422_gamma(void) { + // positive voltage correction + ISSUE_CMD_BYTE(0xE0); + ISSUE_DATA_BYTE(0xD0); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x10); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x26); + ISSUE_DATA_BYTE(0x36); + ISSUE_DATA_BYTE(0x34); + ISSUE_DATA_BYTE(0x4D); + ISSUE_DATA_BYTE(0x18); + ISSUE_DATA_BYTE(0x13); + ISSUE_DATA_BYTE(0x14); + ISSUE_DATA_BYTE(0x2F); + ISSUE_DATA_BYTE(0x34); + + // negative voltage correction + ISSUE_CMD_BYTE(0xE1); + ISSUE_DATA_BYTE(0xD0); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x10); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x09); + ISSUE_DATA_BYTE(0x26); + ISSUE_DATA_BYTE(0x36); + ISSUE_DATA_BYTE(0x53); + ISSUE_DATA_BYTE(0x4C); + ISSUE_DATA_BYTE(0x18); + ISSUE_DATA_BYTE(0x14); + ISSUE_DATA_BYTE(0x14); + ISSUE_DATA_BYTE(0x2F); + ISSUE_DATA_BYTE(0x34); +} + +void lx154a2422_init_seq(void) { + // most recent manual: + // https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf + // TEON: Tearing Effect Line On; V-blanking only + ISSUE_CMD_BYTE(0x35); + ISSUE_DATA_BYTE(0x00); + + // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits + // input) + ISSUE_CMD_BYTE(0x3A); + ISSUE_DATA_BYTE(0x55); + + // CMD2EN: Commands in command table 2 can be executed when EXTC level is Low + ISSUE_CMD_BYTE(0xDF); + ISSUE_DATA_BYTE(0x5A); + ISSUE_DATA_BYTE(0x69); + ISSUE_DATA_BYTE(0x02); + ISSUE_DATA_BYTE(0x01); + + // LCMCTRL: LCM Control: XOR RGB setting + ISSUE_CMD_BYTE(0xC0); + ISSUE_DATA_BYTE(0x20); + + // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.; + // gate scan direction 319 -> 0 + ISSUE_CMD_BYTE(0xE4); + ISSUE_DATA_BYTE(0x1D); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x11); + + // INVOFF (20h): Display Inversion Off + // INVON (21h): Display Inversion On + ISSUE_CMD_BYTE(0x21); + + // the above config is the most important and definitely necessary + + // PWCTRL1: Power Control 1 + ISSUE_CMD_BYTE(0xD0); + ISSUE_DATA_BYTE(0xA4); + ISSUE_DATA_BYTE(0xA1); + + lx154a2422_gamma(); +} + +void lx154a2422_rotate(int degrees) { + uint16_t shift = 0; + +#define RGB (1 << 3) +#define ML (1 << 4) // vertical refresh order +#define MH (1 << 2) // horizontal refresh order +#define MV (1 << 5) +#define MX (1 << 6) +#define MY (1 << 7) + // MADCTL: Memory Data Access Control - reference: + // section 8.12 in the ST7789V manual + uint8_t display_command_parameter = 0; + switch (degrees) { + case 0: + display_command_parameter = 0; + break; + case 90: + display_command_parameter = MV | MX | MH | ML; + shift = 1; + break; + case 180: + display_command_parameter = MX | MY | MH | ML; + shift = 1; + break; + case 270: + display_command_parameter = MV | MY; + break; + } + + ISSUE_CMD_BYTE(0x36); + ISSUE_DATA_BYTE(display_command_parameter); + + if (shift) { + // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is + // gate 80.; gate scan direction 319 -> 0 + ISSUE_CMD_BYTE(0xE4); + ISSUE_DATA_BYTE(0x1D); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0x11); + } else { + // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is + // gate 80.; gate scan direction 319 -> 0 + ISSUE_CMD_BYTE(0xE4); + ISSUE_DATA_BYTE(0x1D); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x11); + } +} diff --git a/core/embed/gdc/gdc_text.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.h similarity index 53% rename from core/embed/gdc/gdc_text.h rename to core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.h index e881e5e33..30a13e359 100644 --- a/core/embed/gdc/gdc_text.h +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.h @@ -17,32 +17,13 @@ * along with this program. If not, see . */ -#ifndef GDC_TEXT_H -#define GDC_TEXT_H +#ifndef LX154A2422_H_ +#define LX154A2422_H_ -#include "gdc_color.h" -#include "gdc_core.h" -#include "gdc_geom.h" +#include "displays/st7789v.h" -#include -#include +void lx154a2422_init_seq(void); +void lx154a2422_gamma(void); +void lx154a2422_rotate(int degrees); -typedef struct { - int font; - - gdc_color_t fg_color; - gdc_color_t bg_color; - - // TODO: horizontal/vertical alignment?? - // TODO: extra offset??? - gdc_offset_t offset; - -} gdc_text_attr_t; - -bool gdc_draw_opaque_text(gdc_t* gdc, gdc_rect_t rect, const char* text, - size_t maxlen, const gdc_text_attr_t* attr); - -bool gdc_draw_blended_text(gdc_t* gdc, gdc_rect_t rect, const char* text, - size_t maxlen, const gdc_text_attr_t* attr); - -#endif // GDC_TEXT_H +#endif diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c new file mode 100644 index 000000000..cb8e9c7a0 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c @@ -0,0 +1,165 @@ +/* + * 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 "../display_io.h" + +void tf15411a_init_seq(void) { + // Inter Register Enable1 + ISSUE_CMD_BYTE(0xFE); + + // Inter Register Enable2 + ISSUE_CMD_BYTE(0xEF); + + // TEON: Tearing Effect Line On; V-blanking only + ISSUE_CMD_BYTE(0x35); + ISSUE_DATA_BYTE(0x00); + + // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits + // input) + ISSUE_CMD_BYTE(0x3A); + ISSUE_DATA_BYTE(0x55); + + // Frame Rate + // ISSUE_CMD_BYTE(0xE8); ISSUE_DATA_BYTE(0x12); ISSUE_DATA_BYTE(0x00); + + // Power Control 2 + ISSUE_CMD_BYTE(0xC3); + ISSUE_DATA_BYTE(0x27); + + // Power Control 3 + ISSUE_CMD_BYTE(0xC4); + ISSUE_DATA_BYTE(0x18); + + // Power Control 4 + ISSUE_CMD_BYTE(0xC9); + ISSUE_DATA_BYTE(0x1F); + + ISSUE_CMD_BYTE(0xC5); + ISSUE_DATA_BYTE(0x0F); + + ISSUE_CMD_BYTE(0xC6); + ISSUE_DATA_BYTE(0x00); + + ISSUE_CMD_BYTE(0xC7); + ISSUE_DATA_BYTE(0x10); + + ISSUE_CMD_BYTE(0xC8); + ISSUE_DATA_BYTE(0x01); + + ISSUE_CMD_BYTE(0xFF); + ISSUE_DATA_BYTE(0x62); + + ISSUE_CMD_BYTE(0x99); + ISSUE_DATA_BYTE(0x3E); + + ISSUE_CMD_BYTE(0x9D); + ISSUE_DATA_BYTE(0x4B); + + ISSUE_CMD_BYTE(0x8E); + ISSUE_DATA_BYTE(0x0F); + + // SET_GAMMA1 + ISSUE_CMD_BYTE(0xF0); + ISSUE_DATA_BYTE(0x8F); + ISSUE_DATA_BYTE(0x1B); + ISSUE_DATA_BYTE(0x05); + ISSUE_DATA_BYTE(0x06); + ISSUE_DATA_BYTE(0x07); + ISSUE_DATA_BYTE(0x42); + + // SET_GAMMA3 + ISSUE_CMD_BYTE(0xF2); + ISSUE_DATA_BYTE(0x5C); + ISSUE_DATA_BYTE(0x1F); + ISSUE_DATA_BYTE(0x12); + ISSUE_DATA_BYTE(0x10); + ISSUE_DATA_BYTE(0x07); + ISSUE_DATA_BYTE(0x43); + + // SET_GAMMA2 + ISSUE_CMD_BYTE(0xF1); + ISSUE_DATA_BYTE(0x59); + ISSUE_DATA_BYTE(0xCF); + ISSUE_DATA_BYTE(0xCF); + ISSUE_DATA_BYTE(0x35); + ISSUE_DATA_BYTE(0x37); + ISSUE_DATA_BYTE(0x8F); + + // SET_GAMMA4 + ISSUE_CMD_BYTE(0xF3); + ISSUE_DATA_BYTE(0x58); + ISSUE_DATA_BYTE(0xCF); + ISSUE_DATA_BYTE(0xCF); + ISSUE_DATA_BYTE(0x35); + ISSUE_DATA_BYTE(0x37); + ISSUE_DATA_BYTE(0x8F); +} + +void tf15411a_rotate(int degrees) { + uint16_t shift = 0; + +#define RGB (1 << 3) +#define ML (1 << 4) // vertical refresh order +#define MH (1 << 2) // horizontal refresh order +#define MV (1 << 5) +#define MX (1 << 6) +#define MY (1 << 7) + // MADCTL: Memory Data Access Control - reference: + // section 9.3 in the ILI9341 manual + // section 6.2.18 in the GC9307 manual + // section 8.12 in the ST7789V manual + uint8_t display_command_parameter = 0; + switch (degrees) { + case 0: + display_command_parameter = 0; + break; + case 90: + display_command_parameter = MV | MX | MH | ML; + shift = 1; + break; + case 180: + display_command_parameter = MX | MY | MH | ML; + shift = 1; + break; + case 270: + display_command_parameter = MV | MY; + break; + } + + display_command_parameter ^= RGB | MY; // XOR RGB and MY settings + + ISSUE_CMD_BYTE(0x36); + ISSUE_DATA_BYTE(display_command_parameter); + + if (shift) { + // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is + // gate 80.; gate scan direction 319 -> 0 + ISSUE_CMD_BYTE(0xE4); + ISSUE_DATA_BYTE(0x1D); + ISSUE_DATA_BYTE(0x00); + ISSUE_DATA_BYTE(0x11); + } else { + // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is + // gate 80.; gate scan direction 319 -> 0 + ISSUE_CMD_BYTE(0xE4); + ISSUE_DATA_BYTE(0x1D); + ISSUE_DATA_BYTE(0x0A); + ISSUE_DATA_BYTE(0x11); + } +} diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.h new file mode 100644 index 000000000..6ff9e3f7d --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.h @@ -0,0 +1,28 @@ +/* + * 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 TF15411A_H_ +#define TF15411A_H_ + +// GC9307 IC controller + +void tf15411a_init_seq(void); +void tf15411a_rotate(int degrees); + +#endif diff --git a/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c new file mode 100644 index 000000000..69936d315 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c @@ -0,0 +1,121 @@ +/* + * 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 TREZOR_BOARD +#include STM32_HAL_H + +#include "display_internal.h" +#include "ili9341_spi.h" +#include "xdisplay.h" + +#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 320) +#error "Incompatible display resolution" +#endif + +// Display driver context. +typedef struct { + // Current display orientation (0, 90, 180, 270) + int orientation_angle; + // Current backlight level ranging from 0 to 255 + int backlight_level; +} display_driver_t; + +// Display driver instance +static display_driver_t g_display_driver; + +void display_init(void) { + display_driver_t *drv = &g_display_driver; + memset(drv, 0, sizeof(display_driver_t)); + + // Initialize LTDC controller + BSP_LCD_Init(); + // Initialize external display controller + ili9341_init(); +} + +void display_reinit(void) { + display_driver_t *drv = &g_display_driver; + memset(drv, 0, sizeof(display_driver_t)); +} + +void display_finish_actions(void) { + // Not used and intentionally left empty +} + +int display_set_backlight(int level) { + display_driver_t *drv = &g_display_driver; + + // Just emulation, not doing anything + drv->backlight_level = level; + return level; +} + +int display_get_backlight(void) { + display_driver_t *drv = &g_display_driver; + + return drv->backlight_level; +} + +int display_set_orientation(int angle) { + display_driver_t *drv = &g_display_driver; + + if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { + // Just emulation, not doing anything + drv->orientation_angle = angle; + } + + return drv->orientation_angle; +} + +int display_get_orientation(void) { + display_driver_t *drv = &g_display_driver; + + return drv->orientation_angle; +} + +void *display_get_frame_addr(void) { return (void *)FRAME_BUFFER_ADDR; } + +void display_refresh(void) { + // Do nothing as using just a single frame buffer +} + +const char *display_save(const char *prefix) { return NULL; } + +void display_clear_save(void) {} + +void display_set_compatible_settings() {} + +// Functions for drawing on display +/* + +// Fills a rectangle with a specified color +void display_fill(gdc_dma2d_t *dp); + +// Copies an RGB565 bitmap to specified rectangle +void display_copy_rgb565(gdc_dma2d_t *dp); + +// Copies a MONO4 bitmap to specified rectangle +void display_copy_mono4(gdc_dma2d_t *dp); + +// Copies a MONO1P bitmap to specified rectangle +void display_copy_mono1p(gdc_dma2d_t *dp); +*/ diff --git a/core/embed/gdc/gdc_dma2d.h b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_internal.h similarity index 55% rename from core/embed/gdc/gdc_dma2d.h rename to core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_internal.h index 13d922c00..c19c63a65 100644 --- a/core/embed/gdc/gdc_dma2d.h +++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_internal.h @@ -17,35 +17,20 @@ * along with this program. If not, see . */ -#ifndef GDC_DMA2D_H -#define GDC_DMA2D_H +#ifndef TREZORHAL_DISPLAY_INTERNAL_H +#define TREZORHAL_DISPLAY_INTERNAL_H -#include -#include +#include TREZOR_BOARD +#include STM32_HAL_H -#include "gdc_color.h" +#include "sdram.h" -typedef struct { - // Destination bitma[ - // Following fields are used for all operations - uint16_t height; - uint16_t width; - void* dst_row; - uint16_t dst_x; - uint16_t dst_y; - uint16_t dst_stride; +// Frame buffer address in external SDRAM +#define FRAME_BUFFER_ADDR ((uint32_t)SDRAM_DEVICE_ADDR) +// Frame buffer size (16-bit per pixel RGB565) +#define FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2) - // Source bitmap - // Used for copying and blending, but src_fg & src_alpha - // fields are also used for fill operation - void* src_row; - uint16_t src_x; - uint16_t src_y; - uint16_t src_stride; - gdc_color_t src_fg; - gdc_color_t src_bg; - uint8_t src_alpha; +// Initializes LTDC controller and I/O pins +void BSP_LCD_Init(void); -} dma2d_params_t; - -#endif // GDC_DMA2D_H \ No newline at end of file +#endif // TREZORHAL_DISPLAY_INTERNAL_H diff --git a/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c new file mode 100644 index 000000000..df3a752c3 --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c @@ -0,0 +1,291 @@ +/* + * 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 TREZOR_BOARD +#include STM32_HAL_H + +#include "display_internal.h" +#include "ili9341_spi.h" +#include "xdisplay.h" + +#define MAX_LAYER_NUMBER 2 + +LTDC_HandleTypeDef LtdcHandler; +static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct; + +/* Default LCD configuration with LCD Layer 1 */ +uint32_t ActiveLayer = 0; + +/** + * @brief Initializes the LCD layers. + * @param LayerIndex: the layer foreground or background. + * @param FB_Address: the layer frame buffer. + */ +void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) { + LTDC_LayerCfgTypeDef Layercfg; + + /* Layer Init */ + Layercfg.WindowX0 = 0; + Layercfg.WindowX1 = DISPLAY_RESX; + Layercfg.WindowY0 = 0; + Layercfg.WindowY1 = DISPLAY_RESY; + Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; + Layercfg.FBStartAdress = FB_Address; + Layercfg.Alpha = 255; + Layercfg.Alpha0 = 0; + Layercfg.Backcolor.Blue = 0; + Layercfg.Backcolor.Green = 0; + Layercfg.Backcolor.Red = 0; + Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; + Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; + Layercfg.ImageWidth = DISPLAY_RESX; + Layercfg.ImageHeight = DISPLAY_RESY; + + HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex); + + // DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE; + // DrawProp[LayerIndex].pFont = &Font24; + // DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK; + + /* Dithering activation */ + HAL_LTDC_EnableDither(&LtdcHandler); +} + +/** + * @brief Selects the LCD Layer. + * @param LayerIndex: the Layer foreground or background. + */ +void BSP_LCD_SelectLayer(uint32_t LayerIndex) { ActiveLayer = LayerIndex; } + +/** + * @brief Sets a LCD Layer visible. + * @param LayerIndex: the visible Layer. + * @param state: new state of the specified layer. + * This parameter can be: ENABLE or DISABLE. + */ +void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState state) { + if (state == ENABLE) { + __HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex); + } else { + __HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex); + } + __HAL_LTDC_RELOAD_CONFIG(&LtdcHandler); +} + +/** + * @brief Sets an LCD Layer visible without reloading. + * @param LayerIndex: Visible Layer + * @param State: New state of the specified layer + * This parameter can be one of the following values: + * @arg ENABLE + * @arg DISABLE + * @retval None + */ +void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex, + FunctionalState State) { + if (State == ENABLE) { + __HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex); + } else { + __HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex); + } + /* Do not Sets the Reload */ +} + +/** + * @brief Configures the Transparency. + * @param LayerIndex: the Layer foreground or background. + * @param Transparency: the Transparency, + * This parameter must range from 0x00 to 0xFF. + */ +void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) { + HAL_LTDC_SetAlpha(&LtdcHandler, Transparency, LayerIndex); +} + +/** + * @brief Configures the transparency without reloading. + * @param LayerIndex: Layer foreground or background. + * @param Transparency: Transparency + * This parameter must be a number between Min_Data = 0x00 and + * Max_Data = 0xFF + * @retval None + */ +void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex, + uint8_t Transparency) { + HAL_LTDC_SetAlpha_NoReload(&LtdcHandler, Transparency, LayerIndex); +} + +/** + * @brief Sets a LCD layer frame buffer address. + * @param LayerIndex: specifies the Layer foreground or background + * @param Address: new LCD frame buffer value + */ +void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) { + HAL_LTDC_SetAddress(&LtdcHandler, Address, LayerIndex); +} + +/** + * @brief Sets an LCD layer frame buffer address without reloading. + * @param LayerIndex: Layer foreground or background + * @param Address: New LCD frame buffer value + * @retval None + */ +void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) { + HAL_LTDC_SetAddress_NoReload(&LtdcHandler, Address, LayerIndex); +} + +void BSP_LCD_Init(void) { + GPIO_InitTypeDef GPIO_InitStructure = {0}; + + /* Enable the LTDC and DMA2D Clock */ + __HAL_RCC_LTDC_CLK_ENABLE(); + __HAL_RCC_DMA2D_CLK_ENABLE(); + + /* Enable GPIOs clock */ + __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + + /* GPIOs Configuration */ + /* + +------------------------+-----------------------+----------------------------+ + + LCD pins assignment + + +------------------------+-----------------------+----------------------------+ + | LCD_TFT R2 <-> PC.10 | LCD_TFT G2 <-> PA.06 | LCD_TFT B2 <-> PD.06 | | + LCD_TFT R3 <-> PB.00 | LCD_TFT G3 <-> PG.10 | LCD_TFT B3 <-> PG.11 | + | LCD_TFT R4 <-> PA.11 | LCD_TFT G4 <-> PB.10 | LCD_TFT B4 <-> PG.12 | | + LCD_TFT R5 <-> PA.12 | LCD_TFT G5 <-> PB.11 | LCD_TFT B5 <-> PA.03 | + | LCD_TFT R6 <-> PB.01 | LCD_TFT G6 <-> PC.07 | LCD_TFT B6 <-> PB.08 | | + LCD_TFT R7 <-> PG.06 | LCD_TFT G7 <-> PD.03 | LCD_TFT B7 <-> PB.09 | + ------------------------------------------------------------------------------- + | LCD_TFT HSYNC <-> PC.06 | LCDTFT VSYNC <-> PA.04 | + | LCD_TFT CLK <-> PG.07 | LCD_TFT DE <-> PF.10 | + ----------------------------------------------------- + */ + + /* GPIOA configuration */ + GPIO_InitStructure.Pin = + GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_11 | GPIO_PIN_12; + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FAST; + GPIO_InitStructure.Alternate = GPIO_AF14_LTDC; + HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); + + /* GPIOB configuration */ + GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + + /* GPIOC configuration */ + GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + + /* GPIOD configuration */ + GPIO_InitStructure.Pin = GPIO_PIN_3 | GPIO_PIN_6; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + + /* GPIOF configuration */ + GPIO_InitStructure.Pin = GPIO_PIN_10; + HAL_GPIO_Init(GPIOF, &GPIO_InitStructure); + + /* GPIOG configuration */ + GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_11; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + + /* GPIOB configuration */ + GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1; + GPIO_InitStructure.Alternate = GPIO_AF9_LTDC; + HAL_GPIO_Init(GPIOB, &GPIO_InitStructure); + + /* GPIOG configuration */ + GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_12; + HAL_GPIO_Init(GPIOG, &GPIO_InitStructure); + + /* On STM32F429I-DISCO, it is not possible to read ILI9341 ID because */ + /* PIN EXTC is not connected to VDD and then LCD_READ_ID4 is not accessible. + */ + /* In this case, ReadID function is bypassed.*/ + /*if(ili9341_drv.ReadID() == ILI9341_ID)*/ + + /* LTDC Configuration ----------------------------------------------------*/ + LtdcHandler.Instance = LTDC; + + /* Timing configuration (Typical configuration from ILI9341 datasheet) + HSYNC=10 (9+1) + HBP=20 (29-10+1) + ActiveW=240 (269-20-10+1) + HFP=10 (279-240-20-10+1) + + VSYNC=2 (1+1) + VBP=2 (3-2+1) + ActiveH=320 (323-2-2+1) + VFP=4 (327-320-2-2+1) + */ + + /* Configure horizontal synchronization width */ + LtdcHandler.Init.HorizontalSync = ILI9341_HSYNC; + /* Configure vertical synchronization height */ + LtdcHandler.Init.VerticalSync = ILI9341_VSYNC; + /* Configure accumulated horizontal back porch */ + LtdcHandler.Init.AccumulatedHBP = ILI9341_HBP; + /* Configure accumulated vertical back porch */ + LtdcHandler.Init.AccumulatedVBP = ILI9341_VBP; + /* Configure accumulated active width */ + LtdcHandler.Init.AccumulatedActiveW = 269; + /* Configure accumulated active height */ + LtdcHandler.Init.AccumulatedActiveH = 323; + /* Configure total width */ + LtdcHandler.Init.TotalWidth = 279; + /* Configure total height */ + LtdcHandler.Init.TotalHeigh = 327; + + /* Configure R,G,B component values for LCD background color */ + LtdcHandler.Init.Backcolor.Red = 0; + LtdcHandler.Init.Backcolor.Blue = 0; + LtdcHandler.Init.Backcolor.Green = 0; + + /* LCD clock configuration */ + /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */ + /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */ + /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 Mhz */ + /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_8 = 48/4 = 6Mhz */ + PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; + PeriphClkInitStruct.PLLSAI.PLLSAIN = 192; + PeriphClkInitStruct.PLLSAI.PLLSAIR = 4; + PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + /* Polarity */ + LtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL; + LtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL; + LtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL; + LtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC; + + HAL_LTDC_Init(&LtdcHandler); + + /* Initialize the LCD Layers */ + BSP_LCD_LayerDefaultInit(1, FRAME_BUFFER_ADDR); + + memset((void *)FRAME_BUFFER_ADDR, 0, FRAME_BUFFER_SIZE); +} diff --git a/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c new file mode 100644 index 000000000..309fb3f0d --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c @@ -0,0 +1,512 @@ + + +#include +#include TREZOR_BOARD +#include "ili9341_spi.h" +#include STM32_HAL_H + +/** + * @brief ILI9341 chip IDs + */ +#define ILI9341_ID 0x9341 + +/** + * @brief ILI9341 Size + */ +#define ILI9341_LCD_PIXEL_WIDTH ((uint16_t)240) +#define ILI9341_LCD_PIXEL_HEIGHT ((uint16_t)320) + +/** + * @brief ILI9341 Timing + */ +/* Timing configuration (Typical configuration from ILI9341 datasheet) + HSYNC=10 (9+1) + HBP=20 (29-10+1) + ActiveW=240 (269-20-10+1) + HFP=10 (279-240-20-10+1) + + VSYNC=2 (1+1) + VBP=2 (3-2+1) + ActiveH=320 (323-2-2+1) + VFP=4 (327-320-2-2+1) +*/ + +/** + * @brief ILI9341 Registers + */ + +/* Level 1 Commands */ +#define LCD_SWRESET 0x01 /* Software Reset */ +#define LCD_READ_DISPLAY_ID 0x04 /* Read display identification information */ +#define LCD_RDDST 0x09 /* Read Display Status */ +#define LCD_RDDPM 0x0A /* Read Display Power Mode */ +#define LCD_RDDMADCTL 0x0B /* Read Display MADCTL */ +#define LCD_RDDCOLMOD 0x0C /* Read Display Pixel Format */ +#define LCD_RDDIM 0x0D /* Read Display Image Format */ +#define LCD_RDDSM 0x0E /* Read Display Signal Mode */ +#define LCD_RDDSDR 0x0F /* Read Display Self-Diagnostic Result */ +#define LCD_SPLIN 0x10 /* Enter Sleep Mode */ +#define LCD_SLEEP_OUT 0x11 /* Sleep out register */ +#define LCD_PTLON 0x12 /* Partial Mode ON */ +#define LCD_NORMAL_MODE_ON 0x13 /* Normal Display Mode ON */ +#define LCD_DINVOFF 0x20 /* Display Inversion OFF */ +#define LCD_DINVON 0x21 /* Display Inversion ON */ +#define LCD_GAMMA 0x26 /* Gamma register */ +#define LCD_DISPLAY_OFF 0x28 /* Display off register */ +#define LCD_DISPLAY_ON 0x29 /* Display on register */ +#define LCD_COLUMN_ADDR 0x2A /* Colomn address register */ +#define LCD_PAGE_ADDR 0x2B /* Page address register */ +#define LCD_GRAM 0x2C /* GRAM register */ +#define LCD_RGBSET 0x2D /* Color SET */ +#define LCD_RAMRD 0x2E /* Memory Read */ +#define LCD_PLTAR 0x30 /* Partial Area */ +#define LCD_VSCRDEF 0x33 /* Vertical Scrolling Definition */ +#define LCD_TEOFF 0x34 /* Tearing Effect Line OFF */ +#define LCD_TEON 0x35 /* Tearing Effect Line ON */ +#define LCD_MAC 0x36 /* Memory Access Control register*/ +#define LCD_VSCRSADD 0x37 /* Vertical Scrolling Start Address */ +#define LCD_IDMOFF 0x38 /* Idle Mode OFF */ +#define LCD_IDMON 0x39 /* Idle Mode ON */ +#define LCD_PIXEL_FORMAT 0x3A /* Pixel Format register */ +#define LCD_WRITE_MEM_CONTINUE 0x3C /* Write Memory Continue */ +#define LCD_READ_MEM_CONTINUE 0x3E /* Read Memory Continue */ +#define LCD_SET_TEAR_SCANLINE 0x44 /* Set Tear Scanline */ +#define LCD_GET_SCANLINE 0x45 /* Get Scanline */ +#define LCD_WDB 0x51 /* Write Brightness Display register */ +#define LCD_RDDISBV 0x52 /* Read Display Brightness */ +#define LCD_WCD 0x53 /* Write Control Display register*/ +#define LCD_RDCTRLD 0x54 /* Read CTRL Display */ +#define LCD_WRCABC 0x55 /* Write Content Adaptive Brightness Control */ +#define LCD_RDCABC 0x56 /* Read Content Adaptive Brightness Control */ +#define LCD_WRITE_CABC 0x5E /* Write CABC Minimum Brightness */ +#define LCD_READ_CABC 0x5F /* Read CABC Minimum Brightness */ +#define LCD_READ_ID1 0xDA /* Read ID1 */ +#define LCD_READ_ID2 0xDB /* Read ID2 */ +#define LCD_READ_ID3 0xDC /* Read ID3 */ + +/* Level 2 Commands */ +#define LCD_RGB_INTERFACE 0xB0 /* RGB Interface Signal Control */ +#define LCD_FRMCTR1 0xB1 /* Frame Rate Control (In Normal Mode) */ +#define LCD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle Mode) */ +#define LCD_FRMCTR3 0xB3 /* Frame Rate Control (In Partial Mode) */ +#define LCD_INVTR 0xB4 /* Display Inversion Control */ +#define LCD_BPC 0xB5 /* Blanking Porch Control register */ +#define LCD_DFC 0xB6 /* Display Function Control register */ +#define LCD_ETMOD 0xB7 /* Entry Mode Set */ +#define LCD_BACKLIGHT1 0xB8 /* Backlight Control 1 */ +#define LCD_BACKLIGHT2 0xB9 /* Backlight Control 2 */ +#define LCD_BACKLIGHT3 0xBA /* Backlight Control 3 */ +#define LCD_BACKLIGHT4 0xBB /* Backlight Control 4 */ +#define LCD_BACKLIGHT5 0xBC /* Backlight Control 5 */ +#define LCD_BACKLIGHT7 0xBE /* Backlight Control 7 */ +#define LCD_BACKLIGHT8 0xBF /* Backlight Control 8 */ +#define LCD_POWER1 0xC0 /* Power Control 1 register */ +#define LCD_POWER2 0xC1 /* Power Control 2 register */ +#define LCD_VCOM1 0xC5 /* VCOM Control 1 register */ +#define LCD_VCOM2 0xC7 /* VCOM Control 2 register */ +#define LCD_NVMWR 0xD0 /* NV Memory Write */ +#define LCD_NVMPKEY 0xD1 /* NV Memory Protection Key */ +#define LCD_RDNVM 0xD2 /* NV Memory Status Read */ +#define LCD_READ_ID4 0xD3 /* Read ID4 */ +#define LCD_PGAMMA 0xE0 /* Positive Gamma Correction register */ +#define LCD_NGAMMA 0xE1 /* Negative Gamma Correction register */ +#define LCD_DGAMCTRL1 0xE2 /* Digital Gamma Control 1 */ +#define LCD_DGAMCTRL2 0xE3 /* Digital Gamma Control 2 */ +#define LCD_INTERFACE 0xF6 /* Interface control register */ + +/* Extend register commands */ +#define LCD_POWERA 0xCB /* Power control A register */ +#define LCD_POWERB 0xCF /* Power control B register */ +#define LCD_DTCA 0xE8 /* Driver timing control A */ +#define LCD_DTCB 0xEA /* Driver timing control B */ +#define LCD_POWER_SEQ 0xED /* Power on sequence register */ +#define LCD_3GAMMA_EN 0xF2 /* 3 Gamma enable register */ +#define LCD_PRC 0xF7 /* Pump ratio control register */ + +/* Size of read registers */ +#define LCD_READ_ID4_SIZE 3 /* Size of Read ID4 */ + +/*############################### SPIx #######################################*/ +#define DISCOVERY_SPIx SPI5 +#define DISCOVERY_SPIx_CLK_ENABLE() __HAL_RCC_SPI5_CLK_ENABLE() +#define DISCOVERY_SPIx_GPIO_PORT GPIOF /* GPIOF */ +#define DISCOVERY_SPIx_AF GPIO_AF5_SPI5 +#define DISCOVERY_SPIx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE() +#define DISCOVERY_SPIx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE() +#define DISCOVERY_SPIx_SCK_PIN GPIO_PIN_7 /* PF.07 */ +#define DISCOVERY_SPIx_MISO_PIN GPIO_PIN_8 /* PF.08 */ +#define DISCOVERY_SPIx_MOSI_PIN GPIO_PIN_9 /* PF.09 */ +/* Maximum Timeout values for flags waiting loops. These timeouts are not based + on accurate values, they just guarantee that the application will not remain + stuck if the SPI communication is corrupted. + You may modify these timeout values depending on CPU frequency and + application conditions (interrupts routines ...). */ +#define SPIx_TIMEOUT_MAX ((uint32_t)0x1000) + +/*################################ LCD #######################################*/ +/* Chip Select macro definition */ +#define LCD_CS_LOW() \ + HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_RESET) +#define LCD_CS_HIGH() \ + HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_SET) + +/* Set WRX High to send data */ +#define LCD_WRX_LOW() \ + HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_RESET) +#define LCD_WRX_HIGH() \ + HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_SET) + +/* Set WRX High to send data */ +#define LCD_RDX_LOW() \ + HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_RESET) +#define LCD_RDX_HIGH() \ + HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_SET) + +/** + * @brief LCD Control pin + */ +#define LCD_NCS_PIN GPIO_PIN_2 +#define LCD_NCS_GPIO_PORT GPIOC +#define LCD_NCS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE() +#define LCD_NCS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE() +/** + * @} + */ +/** + * @brief LCD Command/data pin + */ +#define LCD_WRX_PIN GPIO_PIN_13 +#define LCD_WRX_GPIO_PORT GPIOD +#define LCD_WRX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define LCD_WRX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE() + +#define LCD_RDX_PIN GPIO_PIN_12 +#define LCD_RDX_GPIO_PORT GPIOD +#define LCD_RDX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() +#define LCD_RDX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE() + +static SPI_HandleTypeDef SpiHandle; +uint32_t SpixTimeout = + SPIx_TIMEOUT_MAX; /*. + */ + +#include +#include + +#include TREZOR_BOARD +#include STM32_HAL_H + +#include "xdisplay.h" + +#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 128) +#error "Incompatible display resolution" +#endif + +// This file implements display driver for monochromatic display V-2864KSWEG01 +// with 128x128 resolution connected to CPU via SPI interface. +// +// This type of displayed was used on some preliminary dev kits for T3T1 (Trezor +// TS3) + +// Display driver context. +typedef struct { + // Frame buffer (8-bit Mono) + uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY]; + // Current display orientation (0 or 180) + int orientation_angle; + // Current backlight level ranging from 0 to 255 + int backlight_level; +} display_driver_t; + +// Display driver instance +static display_driver_t g_display_driver; + +// Macros to access display parallel interface + +// FSMC/FMC Bank 1 - NOR/PSRAM 1 +#define DISPLAY_MEMORY_BASE 0x60000000 +#define DISPLAY_MEMORY_PIN 16 + +#define CMD_ADDR *((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE))) +#define DATA_ADDR \ + (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | \ + (1 << DISPLAY_MEMORY_PIN))))) + +#define ISSUE_CMD_BYTE(X) \ + do { \ + (CMD_ADDR) = (X); \ + } while (0) +#define ISSUE_DATA_BYTE(X) \ + do { \ + (DATA_ADDR) = (X); \ + } while (0) + +// --------------------------------------------------------------------------- +// Display controller registers +// --------------------------------------------------------------------------- + +#define OLED_SETCONTRAST 0x81 +#define OLED_DISPLAYALLON_RESUME 0xA4 +#define OLED_DISPLAYALLON 0xA5 +#define OLED_NORMALDISPLAY 0xA6 +#define OLED_INVERTDISPLAY 0xA7 +#define OLED_DISPLAYOFF 0xAE +#define OLED_DISPLAYON 0xAF +#define OLED_SETDISPLAYOFFSET 0xD3 +#define OLED_SETCOMPINS 0xDA +#define OLED_SETVCOMDETECT 0xDB +#define OLED_SETDISPLAYCLOCKDIV 0xD5 +#define OLED_SETPRECHARGE 0xD9 +#define OLED_SETMULTIPLEX 0xA8 +#define OLED_SETLOWCOLUMN 0x00 +#define OLED_SETHIGHCOLUMN 0x10 +#define OLED_SETSTARTLINE 0x40 +#define OLED_MEMORYMODE 0x20 +#define OLED_COMSCANINC 0xC0 +#define OLED_COMSCANDEC 0xC8 +#define OLED_SEGREMAP 0xA0 +#define OLED_CHARGEPUMP 0x8D + +// Dipslay specific initialization sequence +static const uint8_t ug_2828tswig01_init_seq[] = { + OLED_DISPLAYOFF, + // Divide ratio 0, Oscillator Frequency +0% + OLED_SETDISPLAYCLOCKDIV, 0x50, + // Set Memory Addressing Mode - page addressing mode + 0x20, + // Set Contrast Control Register + OLED_SETCONTRAST, 0x8F, + // Set DC-DC Setting: (Double Bytes Command) + 0xAD, 0x8A, + // Set Segment Re-map + OLED_SEGREMAP | 0x01, + // Set COM Output Scan Direction + OLED_COMSCANDEC, + // Set Display Start Line:(Double Bytes Command) + 0xDC, 0x00, + // Set Display Offset:(Double Bytes Command) + OLED_SETDISPLAYOFFSET, 0x00, + // Set Discharge / Pre-Charge Period (Double Bytes Command) + OLED_SETPRECHARGE, 0x22, + // Set VCOM Deselect Level + OLED_SETVCOMDETECT, 0x35, + // Set Multiplex Ratio + OLED_SETMULTIPLEX, 0x7F, + // Set Page + 0xB0, + // Reset column + OLED_SETLOWCOLUMN | 0, OLED_SETHIGHCOLUMN | 0, + + // Set Entire Display Off + // to be clear, this command turns off the function + // which turns entire display on, but it does not clear + // the data in display RAM + OLED_DISPLAYALLON_RESUME, + // Set Normal Display + OLED_NORMALDISPLAY}; + +static void __attribute__((unused)) display_sleep(void) { + // Display OFF + ISSUE_CMD_BYTE(OLED_DISPLAYOFF); + HAL_Delay(5); + // Vpp disable + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET); +} + +static void display_resume(void) { + // Vpp enable + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_SET); + // 100 ms mandatory wait + HAL_Delay(100); + // Display ON + ISSUE_CMD_BYTE(OLED_DISPLAYON); +} + +// Sets the display cursor to the specific row and column +static void display_set_page_and_col(uint8_t page, uint8_t col) { + if (page < (DISPLAY_RESY / 8)) { + ISSUE_CMD_BYTE(0xB0 | (page & 0xF)); + + if (col < DISPLAY_RESX) { + ISSUE_CMD_BYTE(OLED_SETHIGHCOLUMN | ((col & 0x70) >> 4)); + ISSUE_CMD_BYTE(OLED_SETLOWCOLUMN | (col & 0x0F)); + } else { + // Reset column to start + ISSUE_CMD_BYTE(OLED_SETHIGHCOLUMN); + ISSUE_CMD_BYTE(OLED_SETLOWCOLUMN); + } + } +} + +#define COLLECT_ROW_BYTE(src) \ + (0 | (*(src + (0 * DISPLAY_RESX)) ? 128 : 0) | \ + (*(src + (1 * DISPLAY_RESX)) ? 64 : 0) | \ + (*(src + (2 * DISPLAY_RESX)) ? 32 : 0) | \ + (*(src + (3 * DISPLAY_RESX)) ? 16 : 0) | \ + (*(src + (4 * DISPLAY_RESX)) ? 8 : 0) | \ + (*(src + (5 * DISPLAY_RESX)) ? 4 : 0) | \ + (*(src + (6 * DISPLAY_RESX)) ? 2 : 0) | \ + (*(src + (7 * DISPLAY_RESX)) ? 1 : 0)) + +// Copies the framebuffer to the display via SPI interface +static void display_sync_with_fb(void) { + display_driver_t *drv = &g_display_driver; + + for (int y = 0; y < DISPLAY_RESY / 8; y++) { + display_set_page_and_col(y, 0); + uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8]; + for (int x = 0; x < DISPLAY_RESX; x++) { + ISSUE_DATA_BYTE(COLLECT_ROW_BYTE(src)); + src++; + } + } +} + +static void display_init_controller(void) { + // LCD_RST/PC14 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); + // wait 10 milliseconds. only needs to be low for 10 microseconds. + // my dev display module ties display reset and touch panel reset together. + // keeping this low for max(display_reset_time, ctpm_reset_time) aids + // development and does not hurt. + HAL_Delay(10); + + // LCD_RST/PC14 + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); + // max wait time for hardware reset is 120 milliseconds + // (experienced display flakiness using only 5ms wait before sending commands) + HAL_Delay(120); + + // Apply initialization sequence specific to this display controller/panel + for (int i = 0; i < sizeof(ug_2828tswig01_init_seq); i++) { + ISSUE_CMD_BYTE(ug_2828tswig01_init_seq[i]); + } + + // Resume the suspended display + display_resume(); + // Clear display internal framebuffer + display_sync_with_fb(); +} + +static void display_init_interface(void) { + // init peripherals + __HAL_RCC_GPIOC_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); + __HAL_RCC_GPIOE_CLK_ENABLE(); + __HAL_RCC_FMC_CLK_ENABLE(); + + GPIO_InitTypeDef GPIO_InitStructure = {0}; + + // LCD_RST/PC14 + 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_14; + // default to keeping display in reset + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); + HAL_GPIO_Init(GPIOC, &GPIO_InitStructure); + + // VPP Enable + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLDOWN; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + GPIO_InitStructure.Alternate = 0; + GPIO_InitStructure.Pin = GPIO_PIN_8; + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET); + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = GPIO_AF12_FMC; + // LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5 + GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + // LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1 + GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1; + HAL_GPIO_Init(GPIOD, &GPIO_InitStructure); + // LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10 + GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; + HAL_GPIO_Init(GPIOE, &GPIO_InitStructure); + + // Reference UM1725 "Description of STM32F4 HAL and LL drivers", + // section 64.2.1 "How to use this driver" + SRAM_HandleTypeDef display_sram = {0}; + display_sram.Instance = FMC_NORSRAM_DEVICE; + display_sram.Extended = FMC_NORSRAM_EXTENDED_DEVICE; + display_sram.Init.NSBank = FMC_NORSRAM_BANK1; + display_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; + display_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; + display_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8; + display_sram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; + display_sram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; + display_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE; + display_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; + display_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; + display_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; + display_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; + display_sram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; + display_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE; + display_sram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; + display_sram.Init.PageSize = FMC_PAGE_SIZE_NONE; + + // reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6 + FMC_NORSRAM_TimingTypeDef normal_mode_timing = {0}; + normal_mode_timing.AddressSetupTime = 10; + normal_mode_timing.AddressHoldTime = 10; + normal_mode_timing.DataSetupTime = 10; + normal_mode_timing.BusTurnAroundDuration = 0; + normal_mode_timing.CLKDivision = 2; + normal_mode_timing.DataLatency = 2; + normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A; + + HAL_SRAM_Init(&display_sram, &normal_mode_timing, NULL); +} + +void display_init(void) { + display_driver_t *drv = &g_display_driver; + memset(drv, 0, sizeof(display_driver_t)); + + // Initialize GPIO & FSMC controller + display_init_interface(); + // Initialize display controller + display_init_controller(); +} + +void display_reinit(void) { + display_driver_t *drv = &g_display_driver; + memset(drv, 0, sizeof(display_driver_t)); + + // !@# TODO backlight level?? +} + +void display_finish_actions(void) { + /// Not used and intentionally left empty +} + +int display_set_backlight(int level) { + display_driver_t *drv = &g_display_driver; + + if (level != drv->backlight_level) { + if (level >= 0 && level <= 255) { + drv->backlight_level = level; + // Set Contrast Control Register: (Double Bytes Command) + ISSUE_CMD_BYTE(OLED_SETCONTRAST); + ISSUE_CMD_BYTE(level & 0xFF); + } + } + + return drv->backlight_level; +} + +int display_get_backlight(void) { + display_driver_t *drv = &g_display_driver; + + return drv->backlight_level; +} + +int display_set_orientation(int angle) { + display_driver_t *drv = &g_display_driver; + + if (angle != drv->orientation_angle) { + if (angle == 0 || angle == 180) { + drv->orientation_angle = angle; + if (angle == 0) { + // Set Segment Re-map: (A0H - A1H) + ISSUE_CMD_BYTE(OLED_SEGREMAP | 0x01); + // Set COM Output Scan Direction + ISSUE_CMD_BYTE(OLED_COMSCANDEC); + } else { + // Set Segment Re-map: (A0H - A1H) + ISSUE_CMD_BYTE(OLED_SEGREMAP | 0x00); + // Set COM Output Scan Direction + ISSUE_CMD_BYTE(OLED_COMSCANINC); + } + } + } + + return drv->orientation_angle; +} + +int display_get_orientation(void) { + display_driver_t *drv = &g_display_driver; + + return drv->orientation_angle; +} + +void *display_get_frame_addr(void) { + display_driver_t *drv = &g_display_driver; + + return &drv->framebuf[0]; +} + +void display_refresh(void) { display_sync_with_fb(); } + +const char *display_save(const char *prefix) { return NULL; } + +void display_clear_save(void) {} + +void display_set_compatible_settings() {} + +// Functions for drawing on display +/* + +// Fills a rectangle with a specified color +void display_fill(gdc_dma2d_t *dp); + +// Copies an RGB565 bitmap to specified rectangle +void display_copy_rgb565(gdc_dma2d_t *dp); + +// Copies a MONO4 bitmap to specified rectangle +void display_copy_mono4(gdc_dma2d_t *dp); + +// Copies a MONO1P bitmap to specified rectangle +void display_copy_mono1p(gdc_dma2d_t *dp); +*/ diff --git a/core/embed/trezorhal/stm32f4/display/vg-2864/display_driver.c b/core/embed/trezorhal/stm32f4/display/vg-2864/display_driver.c new file mode 100644 index 000000000..9e6f1fb3e --- /dev/null +++ b/core/embed/trezorhal/stm32f4/display/vg-2864/display_driver.c @@ -0,0 +1,351 @@ +/* + * 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 + +#include TREZOR_BOARD +#include STM32_HAL_H + +#include "xdisplay.h" + +#ifdef USE_CONSUMPTION_MASK +#include "consumption_mask.h" +#endif + +#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 64) +#error "Incompatible display resolution" +#endif + +// This file implements display driver for monochromatic display V-2864KSWEG01 +// with 128x64 resolution connected to CPU via SPI interface. +// +// This type of display is used with T3T1 model (Trezor TS3) + +// Display driver context. +typedef struct { + // SPI driver instance + SPI_HandleTypeDef spi; + // Frame buffer (8-bit Mono) + uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY]; + // Current display orientation (0 or 180) + int orientation_angle; + // Current backlight level ranging from 0 to 255 + int backlight_level; +} display_driver_t; + +// Display driver instance +static display_driver_t g_display_driver; + +// Display controller registers +#define OLED_SETCONTRAST 0x81 +#define OLED_DISPLAYALLON_RESUME 0xA4 +#define OLED_DISPLAYALLON 0xA5 +#define OLED_NORMALDISPLAY 0xA6 +#define OLED_INVERTDISPLAY 0xA7 +#define OLED_DISPLAYOFF 0xAE +#define OLED_DISPLAYON 0xAF +#define OLED_SETDISPLAYOFFSET 0xD3 +#define OLED_SETCOMPINS 0xDA +#define OLED_SETVCOMDETECT 0xDB +#define OLED_SETDISPLAYCLOCKDIV 0xD5 +#define OLED_SETPRECHARGE 0xD9 +#define OLED_SETMULTIPLEX 0xA8 +#define OLED_SETLOWCOLUMN 0x00 +#define OLED_SETHIGHCOLUMN 0x10 +#define OLED_SETSTARTLINE 0x40 +#define OLED_MEMORYMODE 0x20 +#define OLED_COMSCANINC 0xC0 +#define OLED_COMSCANDEC 0xC8 +#define OLED_SEGREMAP 0xA0 +#define OLED_CHARGEPUMP 0x8D + +// Display controller initialization sequence +static const uint8_t vg_2864ksweg01_init_seq[] = {OLED_DISPLAYOFF, + OLED_SETDISPLAYCLOCKDIV, + 0x80, + OLED_SETMULTIPLEX, + 0x3F, // 128x64 + OLED_SETDISPLAYOFFSET, + 0x00, + OLED_SETSTARTLINE | 0x00, + OLED_CHARGEPUMP, + 0x14, + OLED_MEMORYMODE, + 0x00, + OLED_SEGREMAP | 0x01, + OLED_COMSCANDEC, + OLED_SETCOMPINS, + 0x12, // 128x64 + OLED_SETCONTRAST, + 0xCF, + OLED_SETPRECHARGE, + 0xF1, + OLED_SETVCOMDETECT, + 0x40, + OLED_DISPLAYALLON_RESUME, + OLED_NORMALDISPLAY, + OLED_DISPLAYON}; + +// Configures SPI driver/controller +static bool display_init_spi(display_driver_t *drv) { + drv->spi.Instance = OLED_SPI; + drv->spi.State = HAL_SPI_STATE_RESET; + drv->spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16; + drv->spi.Init.Direction = SPI_DIRECTION_2LINES; + drv->spi.Init.CLKPhase = SPI_PHASE_1EDGE; + drv->spi.Init.CLKPolarity = SPI_POLARITY_LOW; + drv->spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; + drv->spi.Init.CRCPolynomial = 7; + drv->spi.Init.DataSize = SPI_DATASIZE_8BIT; + drv->spi.Init.FirstBit = SPI_FIRSTBIT_MSB; + drv->spi.Init.NSS = SPI_NSS_HARD_OUTPUT; + drv->spi.Init.TIMode = SPI_TIMODE_DISABLE; + drv->spi.Init.Mode = SPI_MODE_MASTER; + + return (HAL_OK == HAL_SPI_Init(&drv->spi)) ? true : false; +} + +// Sends specified number of bytes to the display via SPI interface +static void display_send_bytes(display_driver_t *drv, const uint8_t *data, + size_t len) { + volatile int32_t timeout = 1000; // !@# why??? + for (int i = 0; i < timeout; i++) + ; + + if (HAL_OK != HAL_SPI_Transmit(&drv->spi, (uint8_t *)data, len, 1000)) { + // TODO: error + return; + } + while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) { + } +} + +#define COLLECT_ROW_BYTE(src) \ + (0 | (*(src + (0 * DISPLAY_RESX)) ? 128 : 0) | \ + (*(src + (1 * DISPLAY_RESX)) ? 64 : 0) | \ + (*(src + (2 * DISPLAY_RESX)) ? 32 : 0) | \ + (*(src + (3 * DISPLAY_RESX)) ? 16 : 0) | \ + (*(src + (4 * DISPLAY_RESX)) ? 8 : 0) | \ + (*(src + (5 * DISPLAY_RESX)) ? 4 : 0) | \ + (*(src + (6 * DISPLAY_RESX)) ? 2 : 0) | \ + (*(src + (7 * DISPLAY_RESX)) ? 1 : 0)) + +// Copies the framebuffer to the display via SPI interface +static void display_sync_with_fb(display_driver_t *drv) { + static const uint8_t cursor_set_seq[3] = {OLED_SETLOWCOLUMN | 0x00, + OLED_SETHIGHCOLUMN | 0x00, + OLED_SETSTARTLINE | 0x00}; + + // SPI select + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); + // Set the cursor to the screen top-left corner + display_send_bytes(drv, &cursor_set_seq[0], sizeof(cursor_set_seq)); + + // SPI deselect + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); + // Set to DATA + HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_SET); + // SPI select + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); + + // Send whole framebuffer to the display + for (int y = 0; y < DISPLAY_RESY / 8; y++) { + uint8_t buff[DISPLAY_RESX]; + uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8]; + + if (drv->orientation_angle == 0) { + for (int x = 0; x < DISPLAY_RESX; x++) { + buff[x] = COLLECT_ROW_BYTE(src); + src++; + } + } else { + for (int x = DISPLAY_RESX - 1; x >= 0; x--) { + buff[x] = COLLECT_ROW_BYTE(src); + src++; + } + } + + if (HAL_OK != HAL_SPI_Transmit(&drv->spi, &buff[0], sizeof(buff), 1000)) { + // TODO: error + return; + } + } + + while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) { + } + + // SPI deselect + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); + // Set to CMD + HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); +} + +void display_init(void) { + display_driver_t *drv = &g_display_driver; + + memset(drv, 0, sizeof(display_driver_t)); + drv->backlight_level = 255; + + OLED_DC_CLK_ENA(); + OLED_CS_CLK_ENA(); + OLED_RST_CLK_ENA(); + OLED_SPI_SCK_CLK_ENA(); + OLED_SPI_MOSI_CLK_ENA(); + OLED_SPI_CLK_ENA(); + + GPIO_InitTypeDef GPIO_InitStructure; + + // Set GPIO for OLED display + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = 0; + GPIO_InitStructure.Pin = OLED_CS_PIN; + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); + HAL_GPIO_Init(OLED_CS_PORT, &GPIO_InitStructure); + GPIO_InitStructure.Pin = OLED_DC_PIN; + HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); + HAL_GPIO_Init(OLED_DC_PORT, &GPIO_InitStructure); + GPIO_InitStructure.Pin = OLED_RST_PIN; + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET); + HAL_GPIO_Init(OLED_RST_PORT, &GPIO_InitStructure); + + // Enable SPI 1 for OLED display + GPIO_InitStructure.Mode = GPIO_MODE_AF_PP; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStructure.Alternate = OLED_SPI_AF; + GPIO_InitStructure.Pin = OLED_SPI_SCK_PIN; + HAL_GPIO_Init(OLED_SPI_SCK_PORT, &GPIO_InitStructure); + GPIO_InitStructure.Pin = OLED_SPI_MOSI_PIN; + HAL_GPIO_Init(OLED_SPI_MOSI_PORT, &GPIO_InitStructure); + + // Initialize SPI controller + display_init_spi(drv); + + // Set to CMD + HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET); + // SPI deselect + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); + + // Reset the LCD + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); + HAL_Delay(1); + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET); + HAL_Delay(1); + HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET); + + // SPI select + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET); + // Send initialization command sequence + display_send_bytes(drv, &vg_2864ksweg01_init_seq[0], + sizeof(vg_2864ksweg01_init_seq)); + // SPI deselect + HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET); + + // Clear display internal framebuffer + display_sync_with_fb(drv); +} + +void display_reinit(void) { + display_driver_t *drv = &g_display_driver; + + memset(drv, 0, sizeof(display_driver_t)); + drv->backlight_level = 255; + + display_init_spi(drv); +} + +void display_finish_actions(void) { + /// Not used and intentionally left empty +} + +int display_set_backlight(int level) { + display_driver_t *drv = &g_display_driver; + + drv->backlight_level = 255; + return drv->backlight_level; +} + +int display_get_backlight(void) { + display_driver_t *drv = &g_display_driver; + + return drv->backlight_level; +} + +int display_set_orientation(int angle) { + display_driver_t *drv = &g_display_driver; + + if (angle != drv->orientation_angle) { + if (angle == 0 || angle == 180) { + drv->orientation_angle = angle; + display_sync_with_fb(drv); + } + } + + return drv->orientation_angle; +} + +int display_get_orientation(void) { + display_driver_t *drv = &g_display_driver; + + return drv->orientation_angle; +} + +void *display_get_frame_addr(void) { + display_driver_t *drv = &g_display_driver; + + return &drv->framebuf[0]; +} + +void display_refresh(void) { + display_driver_t *drv = &g_display_driver; + +#if defined USE_CONSUMPTION_MASK && !defined BOARDLOADER + // This is an intentional randomization of the consumption masking algorithm + // after every change on the display + consumption_mask_randomize(); +#endif + + // Sends the current frame buffer to the display + display_sync_with_fb(drv); +} + +const char *display_save(const char *prefix) { return NULL; } + +void display_clear_save(void) {} + +void display_set_compatible_settings() {} + +/* + +// Fills a rectangle with a specified color +void display_fill(dma2d_params_t *dp) { + +} + +// Copies a MONO1P bitmap to specified rectangle +void display_copy_mono1p(dma2d_params_t *dp) { + +} + +*/ diff --git a/core/embed/trezorhal/stm32f4/displays/ltdc.c b/core/embed/trezorhal/stm32f4/displays/ltdc.c index 0024773ed..66cb7663d 100644 --- a/core/embed/trezorhal/stm32f4/displays/ltdc.c +++ b/core/embed/trezorhal/stm32f4/displays/ltdc.c @@ -46,12 +46,12 @@ uint8_t *const DISPLAY_DATA_ADDRESS = 0; uint16_t cursor_x = 0; uint16_t cursor_y = 0; uint16_t window_x0 = 0; -uint16_t window_y0 = MAX_DISPLAY_RESX - 1; +uint16_t window_y0 = DISPLAY_RESX - 1; uint16_t window_x1 = 0; -uint16_t window_y1 = MAX_DISPLAY_RESY - 1; +uint16_t window_y1 = DISPLAY_RESY - 1; void display_pixeldata(uint16_t c) { - ((uint16_t *)LCD_FRAME_BUFFER)[(cursor_y * MAX_DISPLAY_RESX) + cursor_x] = c; + ((uint16_t *)LCD_FRAME_BUFFER)[(cursor_y * DISPLAY_RESX) + cursor_x] = c; cursor_x++; @@ -83,9 +83,9 @@ void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) { /* Layer Init */ Layercfg.WindowX0 = 0; - Layercfg.WindowX1 = MAX_DISPLAY_RESX; + Layercfg.WindowX1 = DISPLAY_RESX; Layercfg.WindowY0 = 0; - Layercfg.WindowY1 = MAX_DISPLAY_RESY; + Layercfg.WindowY1 = DISPLAY_RESY; Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; Layercfg.FBStartAdress = FB_Address; Layercfg.Alpha = 255; @@ -95,8 +95,8 @@ void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) { Layercfg.Backcolor.Red = 0; Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; - Layercfg.ImageWidth = MAX_DISPLAY_RESX; - Layercfg.ImageHeight = MAX_DISPLAY_RESY; + Layercfg.ImageWidth = DISPLAY_RESX; + Layercfg.ImageHeight = DISPLAY_RESY; HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex); @@ -380,7 +380,7 @@ void display_efficient_clear(void) { uint8_t *display_get_wr_addr(void) { uint32_t address = LCD_FRAME_BUFFER; /* Get the rectangle start address */ - address = (address + (2 * ((cursor_y)*MAX_DISPLAY_RESX + (cursor_x)))); + address = (address + (2 * ((cursor_y)*DISPLAY_RESX + (cursor_x)))); return (uint8_t *)address; } @@ -413,7 +413,7 @@ void display_shift_window(uint16_t pixels) { } uint16_t display_get_window_offset(void) { - return MAX_DISPLAY_RESX - display_get_window_width(); + return DISPLAY_RESX - display_get_window_width(); } void display_finish_actions(void) {} diff --git a/core/embed/trezorhal/stm32f4/displays/ltdc.h b/core/embed/trezorhal/stm32f4/displays/ltdc.h index 2efb2be96..94d83a026 100644 --- a/core/embed/trezorhal/stm32f4/displays/ltdc.h +++ b/core/embed/trezorhal/stm32f4/displays/ltdc.h @@ -5,8 +5,8 @@ #include STM32_HAL_H #define TREZOR_FONT_BPP 4 -#define DISPLAY_FRAMEBUFFER_WIDTH MAX_DISPLAY_RESX -#define DISPLAY_FRAMEBUFFER_HEIGHT MAX_DISPLAY_RESY +#define DISPLAY_FRAMEBUFFER_WIDTH DISPLAY_RESX +#define DISPLAY_FRAMEBUFFER_HEIGHT DISPLAY_RESY #define DISPLAY_FRAMEBUFFER_OFFSET_X 0 #define DISPLAY_FRAMEBUFFER_OFFSET_Y 0 #define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 diff --git a/core/embed/trezorhal/stm32f4/displays/st7789v.c b/core/embed/trezorhal/stm32f4/displays/st7789v.c index 2d1a6e798..7e284da26 100644 --- a/core/embed/trezorhal/stm32f4/displays/st7789v.c +++ b/core/embed/trezorhal/stm32f4/displays/st7789v.c @@ -34,6 +34,8 @@ #include "displays/panels/lx154a2411.h" #include "displays/panels/lx154a2422.h" #include "displays/panels/tf15411a.h" +#else +#include "displays/panels/lx154a2422.h" #endif // using const volatile instead of #define results in binaries that change @@ -241,7 +243,7 @@ int display_orientation(int degrees) { lx154a2422_rotate(degrees, &DISPLAY_PADDING); } #else - DISPLAY_PANEL_ROTATE(degrees, &DISPLAY_PADDING); + lx154a2422_rotate(degrees, &DISPLAY_PADDING); #endif panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); } @@ -292,7 +294,7 @@ void display_init_seq(void) { _154a_init_seq(); } #else - DISPLAY_PANEL_INIT_SEQ(); + lx154a2422_init_seq(); #endif display_unsleep(); diff --git a/core/embed/trezorhal/stm32f4/dma2d_gdc.c b/core/embed/trezorhal/stm32f4/dma2d_gl.c similarity index 81% rename from core/embed/trezorhal/stm32f4/dma2d_gdc.c rename to core/embed/trezorhal/stm32f4/dma2d_gl.c index c3a643db9..5c98fc9d6 100644 --- a/core/embed/trezorhal/stm32f4/dma2d_gdc.c +++ b/core/embed/trezorhal/stm32f4/dma2d_gl.c @@ -20,9 +20,9 @@ #include STM32_HAL_H #include -#include "dma2d.h" -#include "../gdc/gdc_color.h" +#include "gl_color.h" +#include "gl_dma2d.h" static DMA2D_HandleTypeDef dma2d_handle = { .Instance = (DMA2D_TypeDef*)DMA2D_BASE, @@ -50,9 +50,22 @@ bool dma2d_rgb565_fill(const dma2d_params_t* dp) { dp->dst_stride / sizeof(uint16_t) - dp->width; HAL_DMA2D_Init(&dma2d_handle); - HAL_DMA2D_Start(&dma2d_handle, gdc_color_to_color32(dp->src_fg), + HAL_DMA2D_Start(&dma2d_handle, gl_color_to_color32(dp->src_fg), (uint32_t)dp->dst_row + dp->dst_x * sizeof(uint16_t), dp->width, dp->height); + /* + + MODIFY_REG(dma2d_handle.Instance->CR, DMA2D_CR_MODE, DMA2D_R2M); + MODIFY_REG(dma2d_handle.Instance->OPFCCR, DMA2D_OPFCCR_CM, + DMA2D_OUTPUT_RGB565); MODIFY_REG(dma2d_handle.Instance->OOR, + DMA2D_OOR_LO, dp->dst_stride / sizeof(uint16_t) - dp->width); + MODIFY_REG(dma2d_handle.Instance->NLR, (DMA2D_NLR_NL|DMA2D_NLR_PL), + (dp->height| (dp->width << 16))); WRITE_REG(dma2d_handle.Instance->OMAR, + (uint32_t)dp->dst_row + dp->dst_x * sizeof(uint16_t)); + WRITE_REG(dma2d_handle.Instance->OCOLR, + gl_color_to_color32(dp->src_fg)); + ((dma2d_handle).Instance->CR |= DMA2D_CR_START); + */ } else { // STM32F4 can not accelerate blending with the fixed color uint16_t* dst_ptr = (uint16_t*)dp->dst_row + dp->dst_x; @@ -60,7 +73,7 @@ bool dma2d_rgb565_fill(const dma2d_params_t* dp) { uint8_t alpha = dp->src_alpha; while (height-- > 0) { for (int x = 0; x < dp->width; x++) { - dst_ptr[x] = gdc_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha); + dst_ptr[x] = gl_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha); } dst_ptr += dp->dst_stride / sizeof(*dst_ptr); } @@ -70,27 +83,27 @@ bool dma2d_rgb565_fill(const dma2d_params_t* dp) { } /* -static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) { +static void dma2d_config_clut(uint32_t layer, gl_color_t fg, gl_color_t bg) { #define LAYER_COUNT 2 #define GRADIENT_STEPS 16 static struct { - gdc_color32_t gradient[GRADIENT_STEPS]; + gl_color32_t gradient[GRADIENT_STEPS]; } cache[LAYER_COUNT] = { 0 }; if (layer >= LAYER_COUNT) { return; } - uint32_t c_fg = gdc_color_to_color32(fg); - uint32_t c_bg = gdc_color_to_color32(bg); + uint32_t c_fg = gl_color_to_color32(fg); + uint32_t c_bg = gl_color_to_color32(bg); uint32_t* gradient = cache[layer].gradient; if (c_bg != gradient[0] || c_fg != gradient[GRADIENT_STEPS - 1]) { for (int step = 0; step < GRADIENT_STEPS; step++) { - gradient[step] = gdc_color32_blend_a4(fg, bg, step); + gradient[step] = gl_color32_blend_a4(fg, bg, step); } DMA2D_CLUTCfgTypeDef clut; @@ -105,13 +118,13 @@ static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) { } }*/ -static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) { +static void dma2d_config_clut(uint32_t layer, gl_color_t fg, gl_color_t bg) { #define LAYER_COUNT 2 #define GRADIENT_STEPS 16 static struct { - gdc_color_t c_fg; - gdc_color_t c_bg; + gl_color_t c_fg; + gl_color_t c_bg; } cache[LAYER_COUNT] = {0}; if (layer >= LAYER_COUNT) { @@ -126,7 +139,7 @@ static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) { cache[layer].c_bg = bg; for (int step = 0; step < GRADIENT_STEPS; step++) { - clut[step] = gdc_color32_blend_a4(fg, bg, step); + clut[step] = gl_color32_blend_a4(fg, bg, step); } DMA2D_CLUTCfgTypeDef clut; @@ -139,7 +152,7 @@ static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) { } static void dma2d_rgb565_copy_mono4_first_col(dma2d_params_t* dp, - const gdc_color16_t* gradient) { + const gl_color16_t* gradient) { uint16_t* dst_ptr = (uint16_t*)dp->dst_row + dp->dst_x; uint8_t* src_ptr = (uint8_t*)dp->src_row + dp->src_x / 2; @@ -154,7 +167,7 @@ static void dma2d_rgb565_copy_mono4_first_col(dma2d_params_t* dp, } static void dma2d_rgb565_copy_mono4_last_col(dma2d_params_t* dp, - const gdc_color16_t* gradient) { + const gl_color16_t* gradient) { uint16_t* dst_ptr = (uint16_t*)dp->dst_row + (dp->dst_x + dp->width - 1); uint8_t* src_ptr = (uint8_t*)dp->src_row + (dp->src_x + dp->width - 1) / 2; @@ -169,7 +182,7 @@ static void dma2d_rgb565_copy_mono4_last_col(dma2d_params_t* dp, } bool dma2d_rgb565_copy_mono4(const dma2d_params_t* params) { - const gdc_color16_t* src_gradient = NULL; + const gl_color16_t* src_gradient = NULL; dma2d_params_t dp_copy = *params; dma2d_params_t* dp = &dp_copy; @@ -179,7 +192,7 @@ bool dma2d_rgb565_copy_mono4(const dma2d_params_t* params) { if (dp->src_x & 1) { // First column of mono4 bitmap is odd // Use the CPU to draw the first column - src_gradient = gdc_color16_gradient_a4(dp->src_fg, dp->src_bg); + src_gradient = gl_color16_gradient_a4(dp->src_fg, dp->src_bg); dma2d_rgb565_copy_mono4_first_col(dp, src_gradient); dp->dst_x += 1; dp->src_x += 1; @@ -190,7 +203,7 @@ bool dma2d_rgb565_copy_mono4(const dma2d_params_t* params) { // The width is odd // Use the CPU to draw the last column if (src_gradient == NULL) { - src_gradient = gdc_color16_gradient_a4(dp->src_fg, dp->src_bg); + src_gradient = gl_color16_gradient_a4(dp->src_fg, dp->src_bg); } dma2d_rgb565_copy_mono4_last_col(dp, src_gradient); dp->width -= 1; @@ -249,8 +262,8 @@ static void dma2d_rgb565_blend_mono4_first_col(const dma2d_params_t* dp) { while (height-- > 0) { uint8_t fg_alpha = src_ptr[0] >> 4; - dst_ptr[0] = gdc_color16_blend_a4( - dp->src_fg, gdc_color16_to_color(dst_ptr[0]), fg_alpha); + dst_ptr[0] = gl_color16_blend_a4(dp->src_fg, + gl_color16_to_color(dst_ptr[0]), fg_alpha); dst_ptr += dp->dst_stride / sizeof(*dst_ptr); src_ptr += dp->src_stride / sizeof(*src_ptr); } @@ -264,8 +277,8 @@ static void dma2d_rgb565_blend_mono4_last_col(const dma2d_params_t* dp) { while (height-- > 0) { uint8_t fg_alpha = src_ptr[0] & 0x0F; - dst_ptr[0] = gdc_color16_blend_a4( - dp->src_fg, gdc_color16_to_color(dst_ptr[0]), fg_alpha); + dst_ptr[0] = gl_color16_blend_a4(dp->src_fg, + gl_color16_to_color(dst_ptr[0]), fg_alpha); dst_ptr += dp->dst_stride / sizeof(*dst_ptr); src_ptr += dp->src_stride / sizeof(*src_ptr); } @@ -303,7 +316,7 @@ bool dma2d_rgb565_blend_mono4(const dma2d_params_t* params) { dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4; dma2d_handle.LayerCfg[1].InputOffset = dp->src_stride * 2 - dp->width; dma2d_handle.LayerCfg[1].AlphaMode = 0; - dma2d_handle.LayerCfg[1].InputAlpha = gdc_color_to_color32(dp->src_fg); + dma2d_handle.LayerCfg[1].InputAlpha = gl_color_to_color32(dp->src_fg); HAL_DMA2D_ConfigLayer(&dma2d_handle, 1); dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565; diff --git a/core/embed/trezorhal/stm32f4/touch/ft6x36.c b/core/embed/trezorhal/stm32f4/touch/ft6x36.c index e2729541c..e1bb494fb 100644 --- a/core/embed/trezorhal/stm32f4/touch/ft6x36.c +++ b/core/embed/trezorhal/stm32f4/touch/ft6x36.c @@ -260,8 +260,8 @@ uint32_t touch_read(void) { // first touch) (tested with FT6206) const uint32_t event_flag = touch_data[3] & 0xC0; if (touch_data[1] == GESTURE_NO_GESTURE) { - xy = TRANSFORM_TOUCH_COORDS((X_POS_MSB << 8) | X_POS_LSB, - (Y_POS_MSB << 8) | Y_POS_LSB); + xy = touch_pack_xy((X_POS_MSB << 8) | X_POS_LSB, + (Y_POS_MSB << 8) | Y_POS_LSB); if ((number_of_touch_points == 1) && (event_flag == EVENT_PRESS_DOWN)) { touching = 1; return TOUCH_START | xy; diff --git a/core/embed/trezorhal/stm32u5/display/st-7789 b/core/embed/trezorhal/stm32u5/display/st-7789 new file mode 120000 index 000000000..3ad01c673 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/display/st-7789 @@ -0,0 +1 @@ +../../stm32f4/display/st-7789 \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c new file mode 100644 index 000000000..97eba660b --- /dev/null +++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c @@ -0,0 +1,135 @@ +/* + * 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 TREZOR_BOARD +#include STM32_HAL_H + +#include "display_internal.h" +#include "xdisplay.h" + +#if (DISPLAY_RESX != 480) || (DISPLAY_RESY != 480) +#error "Incompatible display resolution" +#endif + +// Display driver context. +typedef struct { + // Current display orientation (0, 90, 180, 270) + int orientation_angle; + // Current backlight level ranging from 0 to 255 + int backlight_level; +} display_driver_t; + +// Display driver instance +static display_driver_t g_display_driver; + +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); + + // Clear framebuffers + memset(physical_frame_buffer_0, 0x00, PHYSICAL_FRAME_BUFFER_SIZE); + memset(physical_frame_buffer_1, 0x00, PHYSICAL_FRAME_BUFFER_SIZE); + + BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT); + BSP_LCD_SetBrightness(0, 100); + BSP_LCD_DisplayOn(0); +} + +void display_reinit(void) { + BSP_LCD_Reinit(0); + if (current_frame_buffer == 0) { + BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); + } else { + BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); + } +} + +void display_finish_actions(void) { + // Not used and intentionally left empty +} + +int display_set_backlight(int level) { + display_driver_t* drv = &g_display_driver; + + // Just emulation, not doing anything + drv->backlight_level = level; + return level; +} + +int display_get_backlight(void) { + display_driver_t* drv = &g_display_driver; + + return drv->orientation_angle; +} + +int display_set_orientation(int angle) { + display_driver_t* drv = &g_display_driver; + + if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { + // Just emulation, not doing anything + drv->orientation_angle = angle; + } + + return drv->orientation_angle; +} + +int display_get_orientation(void) { + display_driver_t* drv = &g_display_driver; + + return drv->orientation_angle; +} + +const char* display_save(const char* prefix) { return NULL; } + +void display_clear_save(void) {} + +void display_set_compatible_settings() {} + +// Functions for drawing on display +/* + +// Fills a rectangle with a specified color +void display_fill(gdc_dma2d_t *dp); + +// Copies an RGB565 bitmap to specified rectangle +void display_copy_rgb565(gdc_dma2d_t *dp); + +// Copies a MONO4 bitmap to specified rectangle +void display_copy_mono4(gdc_dma2d_t *dp); + +// Copies a MONO1P bitmap to specified rectangle +void display_copy_mono1p(gdc_dma2d_t *dp); +*/ diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c new file mode 100644 index 000000000..741f48fe5 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c @@ -0,0 +1,60 @@ +/* + * 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 TREZOR_BOARD +#include STM32_HAL_H + +#include "display_internal.h" + +// Physical frame buffers in internal SRAM memory +__attribute__((section(".fb1"))) +ALIGN_32BYTES(uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]); + +__attribute__((section(".fb2"))) +ALIGN_32BYTES(uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]); + +// The current frame buffer selector at fixed memory address +// It's shared between bootloaders and the firmware +__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer = + 0; + +void* display_get_frame_addr(void) { + if (current_frame_buffer == 0) { + return (void*)GFXMMU_VIRTUAL_BUFFER0_BASE_S; + } else { + return (void*)GFXMMU_VIRTUAL_BUFFER1_BASE_S; + } +} + +void display_refresh(void) { + current_frame_buffer = current_frame_buffer ? 0 : 1; + + if (current_frame_buffer == 0) { + BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S); + memcpy(physical_frame_buffer_1, physical_frame_buffer_0, + PHYSICAL_FRAME_BUFFER_SIZE); + } else { + BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S); + memcpy(physical_frame_buffer_0, physical_frame_buffer_1, + PHYSICAL_FRAME_BUFFER_SIZE); + } +} \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_gfxmmu_lut.h b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_gfxmmu_lut.h new file mode 100644 index 000000000..86528b9d9 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_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[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/display/stm32u5a9j-dk/display_internal.h b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_internal.h new file mode 100644 index 000000000..45a934ed0 --- /dev/null +++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_internal.h @@ -0,0 +1,55 @@ +/* + * 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_DISPLAY_INTERNAL_H +#define TREZOR_HAL_DISPLAY_INTERNAL_H + +#include + +// Size of the physical frame buffer in bytes +// +// It's smaller than size of the virtual framebuffer +// due to used GFXMMU settings +#define PHYSICAL_FRAME_BUFFER_SIZE 184320 + +// Physical frame buffers in internal SRAM memory +// +// Both frame buffers layes in the fixed addresses that +// are shared between bootloaders and the firmware. +extern uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]; +extern uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]; + +// The current frame buffer selector at fixed memory address +// +// The variable address is shared between bootloaders and the firmware +extern uint32_t current_frame_buffer; + +// LCD orientations +#define LCD_ORIENTATION_PORTRAIT 0U +#define LCD_ORIENTATION_LANDSCAPE 1U +#define LCD_ORIENTATION_PORTRAIT_ROT180 2U +#define LCD_ORIENTATION_LANDSCAPE_ROT180 3U + +int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation); +int32_t BSP_LCD_Reinit(uint32_t Instance); +int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness); +int32_t BSP_LCD_DisplayOn(uint32_t Instance); +int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr); + +#endif // TREZOR_HAL_DISPLAY_INTERNAL_H diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c new file mode 100644 index 000000000..aad64772d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c @@ -0,0 +1,1562 @@ +/** + ****************************************************************************** + * @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 TREZOR_BOARD +#include STM32_HAL_H + +#include "display_internal.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 + +#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 + +#include "display_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 + * @{ + */ + +#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}; + +/** + * @} + */ + +/** @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)physical_frame_buffer_0; + hgfxmmu->Init.Buffers.Buf1Address = (uint32_t)physical_frame_buffer_1; + 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); +} + +int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr) { + int32_t status = BSP_ERROR_NONE; + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, fb_addr); + } + + return status; +} + +int32_t BSP_LCD_Reinit(uint32_t Instance) { + int32_t status = BSP_ERROR_NONE; + if (Instance >= LCD_INSTANCES_NBR) { + status = BSP_ERROR_WRONG_PARAM; + } else { + // 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); + } + + return status; +} diff --git a/core/embed/trezorhal/stm32u5/display/vg-2864 b/core/embed/trezorhal/stm32u5/display/vg-2864 new file mode 120000 index 000000000..88c9a8fad --- /dev/null +++ b/core/embed/trezorhal/stm32u5/display/vg-2864 @@ -0,0 +1 @@ +../../stm32f4/display/vg-2864 \ No newline at end of file diff --git a/core/embed/trezorhal/stm32u5/displays/dsi.h b/core/embed/trezorhal/stm32u5/displays/dsi.h index a717e4bb7..913adb369 100644 --- a/core/embed/trezorhal/stm32u5/displays/dsi.h +++ b/core/embed/trezorhal/stm32u5/displays/dsi.h @@ -3,10 +3,6 @@ #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 diff --git a/core/embed/trezorhal/stm32u5/dma2d_gl.c b/core/embed/trezorhal/stm32u5/dma2d_gl.c new file mode 120000 index 000000000..84c2c932d --- /dev/null +++ b/core/embed/trezorhal/stm32u5/dma2d_gl.c @@ -0,0 +1 @@ +../stm32f4/dma2d_gl.c \ No newline at end of file diff --git a/core/embed/trezorhal/unix/display_driver.c b/core/embed/trezorhal/unix/display_driver.c new file mode 100644 index 000000000..7f2946aea --- /dev/null +++ b/core/embed/trezorhal/unix/display_driver.c @@ -0,0 +1,409 @@ +/* + * 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 . + */ + +#define _GNU_SOURCE + +#include + +#include +#include + +#include "common.h" +#include "profile.h" + +#define EMULATOR_BORDER 16 + +#if defined TREZOR_MODEL_T + +#ifdef TREZOR_EMULATOR_RASPI +#define WINDOW_WIDTH 480 +#define WINDOW_HEIGHT 320 +#define TOUCH_OFFSET_X 110 +#define TOUCH_OFFSET_Y 40 +#else +#define WINDOW_WIDTH 400 +#define WINDOW_HEIGHT 600 +#define TOUCH_OFFSET_X 80 +#define TOUCH_OFFSET_Y 110 +#endif + +#elif defined TREZOR_MODEL_1 + +#define WINDOW_WIDTH 200 +#define WINDOW_HEIGHT 340 +#define TOUCH_OFFSET_X 36 +#define TOUCH_OFFSET_Y 92 + +#elif defined TREZOR_MODEL_R + +#define WINDOW_WIDTH 193 +#define WINDOW_HEIGHT 339 +#define TOUCH_OFFSET_X 32 +#define TOUCH_OFFSET_Y 84 + +#elif defined TREZOR_MODEL_T3T1 + +#define WINDOW_WIDTH 400 +#define WINDOW_HEIGHT 600 +#define TOUCH_OFFSET_X 80 +#define TOUCH_OFFSET_Y 110 + +#else +#error Unknown Trezor model +#endif + +typedef struct { + // Current display orientation (0 or 180) + int orientation_angle; + // Current backlight level ranging from 0 to 255 + int backlight_level; + + SDL_Window *window; + SDL_Renderer *renderer; + SDL_Surface *buffer; + SDL_Texture *texture; + SDL_Texture *background; + SDL_Surface *prev_saved; + +#if DISPLAY_MONO + // SDL2 does not support 8bit surface/texture + // and we have to simulate it + uint8_t mono_framebuf[DISPLAY_RESX * DISPLAY_RESY]; +#endif + +} display_driver_t; + +static display_driver_t g_display_driver; + +//!@# TODO get rid of this... +int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY; +int sdl_touch_offset_x, sdl_touch_offset_y; + +void display_deinit(void) { + display_driver_t *drv = &g_display_driver; + + SDL_FreeSurface(drv->prev_saved); + SDL_FreeSurface(drv->buffer); + if (drv->background != NULL) { + SDL_DestroyTexture(drv->background); + } + if (drv->texture != NULL) { + SDL_DestroyTexture(drv->texture); + } + if (drv->renderer != NULL) { + SDL_DestroyRenderer(drv->renderer); + } + if (drv->window != NULL) { + SDL_DestroyWindow(drv->window); + } + SDL_Quit(); +} + +void display_init(void) { + display_driver_t *drv = &g_display_driver; + + if (SDL_Init(SDL_INIT_VIDEO) != 0) { + printf("%s\n", SDL_GetError()); + ensure(secfalse, "SDL_Init error"); + } + atexit(display_deinit); + + char *window_title = NULL; + char *window_title_alloc = NULL; + if (asprintf(&window_title_alloc, "Trezor^emu: %s", profile_name()) > 0) { + window_title = window_title_alloc; + } else { + window_title = "Trezor^emu"; + window_title_alloc = NULL; + } + + drv->window = + SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT, +#ifdef TREZOR_EMULATOR_RASPI + SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN +#else + SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI +#endif + ); + free(window_title_alloc); + if (!drv->window) { + printf("%s\n", SDL_GetError()); + ensure(secfalse, "SDL_CreateWindow error"); + } + drv->renderer = SDL_CreateRenderer(drv->window, -1, SDL_RENDERER_SOFTWARE); + if (!drv->renderer) { + printf("%s\n", SDL_GetError()); + SDL_DestroyWindow(drv->window); + ensure(secfalse, "SDL_CreateRenderer error"); + } + SDL_SetRenderDrawColor(drv->renderer, 0, 0, 0, 255); + SDL_RenderClear(drv->renderer); + + drv->buffer = SDL_CreateRGBSurface(0, DISPLAY_RESX, DISPLAY_RESY, 16, 0xF800, + 0x07E0, 0x001F, 0x0000); + drv->texture = SDL_CreateTexture(drv->renderer, SDL_PIXELFORMAT_RGB565, + SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX, + DISPLAY_RESY); + SDL_SetTextureBlendMode(drv->texture, SDL_BLENDMODE_BLEND); +#ifdef __APPLE__ + // macOS Mojave SDL black screen workaround + SDL_PumpEvents(); + SDL_SetWindowSize(WINDOW, WINDOW_WIDTH, WINDOW_HEIGHT); +#endif +#ifdef TREZOR_EMULATOR_RASPI +#include "background_raspi.h" + drv->background = IMG_LoadTexture_RW( + drv->renderer, + SDL_RWFromMem(background_raspi_jpg, background_raspi_jpg_len), 0); +#else +#if defined TREZOR_MODEL_T +#include "background_T.h" + drv->background = IMG_LoadTexture_RW( + drv->renderer, SDL_RWFromMem(background_T_jpg, background_T_jpg_len), 0); +#elif defined TREZOR_MODEL_1 +#include "background_1.h" + drv->background = IMG_LoadTexture_RW( + drv->renderer, SDL_RWFromMem(background_1_jpg, background_1_jpg_len), 0); +#elif defined TREZOR_MODEL_R +#include "background_T2B1.h" + drv->background = IMG_LoadTexture_RW( + drv->renderer, + SDL_RWFromMem(background_T2B1_png, background_T2B1_png_len), 0); +#endif +#endif + if (drv->background) { + SDL_SetTextureBlendMode(drv->background, SDL_BLENDMODE_NONE); + sdl_touch_offset_x = TOUCH_OFFSET_X; + sdl_touch_offset_y = TOUCH_OFFSET_Y; + } else { + SDL_SetWindowSize(drv->window, DISPLAY_RESX + 2 * EMULATOR_BORDER, + DISPLAY_RESY + 2 * EMULATOR_BORDER); + sdl_touch_offset_x = EMULATOR_BORDER; + sdl_touch_offset_y = EMULATOR_BORDER; + } +#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R + // T1 and TR do not have backlight capabilities in hardware, so + // setting its value here for emulator to avoid + // calling any `set_backlight` functions + drv->backlight_level = 255; +#else + drv->backlight_level = 0; +#endif +#ifdef TREZOR_EMULATOR_RASPI + drv->orientation_angle = 270; + SDL_ShowCursor(SDL_DISABLE); +#else + drv->orientation_angle = 0; +#endif +} + +void display_reinit(void) { + // not used +} + +void display_finish_actions(void) { + // not used +} + +int display_set_backlight(int level) { + display_driver_t *drv = &g_display_driver; + +#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R + level = 255; +#endif + + if (drv->backlight_level != level && level >= 0 && level <= 255) { + drv->backlight_level = level; + display_refresh(); + } + + return drv->backlight_level; +} + +int display_get_backlight(void) { + display_driver_t *drv = &g_display_driver; + return drv->backlight_level; +} + +int display_set_orientation(int angle) { + display_driver_t *drv = &g_display_driver; + if (angle != drv->orientation_angle) { +#if defined TREZOR_MODEL_T || defined TREZOR_MODEL_T3T1 + if (angle == 0 || angle == 90 || angle == 180 || angle == 270) { +#elif defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R + if (angle == 0 || angle == 180) { +#else +#error Unknown Trezor model +#endif + drv->orientation_angle = angle; + display_refresh(); + } + } + return drv->orientation_angle; +} + +int display_get_orientation(void) { + display_driver_t *drv = &g_display_driver; + return drv->orientation_angle; +} + +#ifdef XFRAMEBUFFER +void *display_get_frame_addr(void) { + display_driver_t *drv = &g_display_driver; + +#ifdef DISPLAY_MONO + return drv->mono_framebuf; +#else + // !@# pitch??? + return drv->buffer->pixels; +#endif +} + +#else // XFRAMEBUFFER + +void display_wait_for_sync(void) { + // not used +} +#endif + +#ifdef DISPLAY_MONO +// Copies driver's monochromatic framebuffer into the RGB framebuffer used by +// SDL +void copy_mono_framebuf(display_driver_t *drv) { + for (int y = 0; y < DISPLAY_RESY; y++) { + uint16_t *dst = + (uint16_t *)((uint8_t *)drv->buffer->pixels + drv->buffer->pitch * y); + uint8_t *src = &drv->mono_framebuf[y * DISPLAY_RESX]; + for (int x = 0; x < DISPLAY_RESX; x++) { + uint8_t lum = src[x]; + dst[x] = gl_color16_rgb(lum, lum, lum); + } + } +} +#endif + +void display_refresh(void) { + display_driver_t *drv = &g_display_driver; + + if (!drv->renderer) { + display_init(); + } + +#ifdef DISPLAY_MONO + copy_mono_framebuf(drv); +#endif + + if (drv->background) { + const SDL_Rect r = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + SDL_RenderCopy(drv->renderer, drv->background, NULL, &r); + } else { + SDL_RenderClear(drv->renderer); + } + // Show the display buffer + SDL_UpdateTexture(drv->texture, NULL, drv->buffer->pixels, + drv->buffer->pitch); +#define BACKLIGHT_NORMAL 150 + SDL_SetTextureAlphaMod( + drv->texture, MIN(255, 255 * drv->backlight_level / BACKLIGHT_NORMAL)); + if (drv->background) { + const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX, + DISPLAY_RESY}; + SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r, + drv->orientation_angle, NULL, 0); + } else { + const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX, + DISPLAY_RESY}; + SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r, + drv->orientation_angle, NULL, 0); + } + SDL_RenderPresent(drv->renderer); +} + +void display_set_compatible_settings(void) { + // not used +} + +void display_fill(const dma2d_params_t *dp) { + display_driver_t *drv = &g_display_driver; + + dma2d_params_t dp_new = *dp; + dp_new.dst_row = + (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * dp_new.dst_y); + dp_new.dst_stride = drv->buffer->pitch; + + rgb565_fill(&dp_new); +} + +void display_copy_rgb565(const dma2d_params_t *dp) { + display_driver_t *drv = &g_display_driver; + + dma2d_params_t dp_new = *dp; + dp_new.dst_row = + (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * dp_new.dst_y); + dp_new.dst_stride = drv->buffer->pitch; + + rgb565_copy_rgb565(&dp_new); +} + +void display_copy_mono4(const dma2d_params_t *dp) { + // !@# TODO +} + +void display_copy_mono1p(const dma2d_params_t *dp) { + // !@# TODO +} + +const char *display_save(const char *prefix) { + display_driver_t *drv = &g_display_driver; + + if (!drv->renderer) { + display_init(); + } + static int count; + static char filename[256]; + // take a cropped view of the screen contents + const SDL_Rect rect = {0, 0, DISPLAY_RESX, DISPLAY_RESY}; + SDL_Surface *crop = SDL_CreateRGBSurface( + drv->buffer->flags, rect.w, rect.h, drv->buffer->format->BitsPerPixel, + drv->buffer->format->Rmask, drv->buffer->format->Gmask, + drv->buffer->format->Bmask, drv->buffer->format->Amask); + SDL_BlitSurface(drv->buffer, &rect, crop, NULL); + // compare with previous screen, skip if equal + if (drv->prev_saved != NULL) { + if (memcmp(drv->prev_saved->pixels, crop->pixels, crop->pitch * crop->h) == + 0) { + SDL_FreeSurface(crop); + return filename; + } + SDL_FreeSurface(drv->prev_saved); + } + // save to png + snprintf(filename, sizeof(filename), "%s%08d.png", prefix, count++); + IMG_SavePNG(crop, filename); + drv->prev_saved = crop; + return filename; +} + +void display_clear_save(void) { + display_driver_t *drv = &g_display_driver; + + SDL_FreeSurface(drv->prev_saved); + drv->prev_saved = NULL; +} diff --git a/core/embed/trezorhal/xdisplay.h b/core/embed/trezorhal/xdisplay.h new file mode 100644 index 000000000..a63f80956 --- /dev/null +++ b/core/embed/trezorhal/xdisplay.h @@ -0,0 +1,135 @@ +/* + * 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_XDISPLAY_H +#define TREZORHAL_XDISPLAY_H + +#include +#include "gl_dma2d.h" + +#include TREZOR_BOARD + +// This is a universal API for controlling different types of display +// controllers. +// +// Currently, following displays displays are supported +// +// VG-2864KSWEG01 - OLED Mono / 128x64 pixels / SPI +// - Model T1B1 / Model T2B1 +// +// UG-2828SWIG01 - OLED Mono / 128x128 pixels / Parallel +// - Early revisions of T2B1 +// +// ST7789V - TFT RGB / 240x240 pixels / Parallel +// - Model T2T1 / Model T3T1 +// +// ILI9341 - TFT RGB / 320x240 pixels / Parallel / LTDC + SPI +// - STM32F429I-DISC1 Discovery Board +// +// MIPI - +// - STM32U5A9J-DK Discovery Board + +// Fully initializes the display controller. +void display_init(void); + +// Called in application to reinitialize an already initialized display +// controller without any distrubing visible effect (blinking, etc.). +void display_reinit(void); + +// Waits for any backround operations (such as DMA copying) +// and returns. +// +// The function provides a barrier when jumping between +// boardloader/bootloader and firmware. +void display_finish_actions(void); + +// Sets display backlight level ranging from 0 (off)..255 (maximum). +// +// The default backligt level is 0. Without settings it +// to some higher value the displayed pixels are not visible. +// Beware that his also applies to the emulator. +// +// Returns the set level (usually the same value or the +// closest value to the `level` argument) +int display_set_backlight(int level); + +// Gets current display level ranging from 0 (off)..255 (maximum). +int display_get_backlight(void); + +// Sets the display orientation. +// +// May accept one of following values: 0, 90, 180, 270 +// but accepted values are model-dependent. +// Default display orientation is always 0. +// +// Returns the set orientation +int display_set_orientation(int angle); + +// Gets the display's current orientation +// +// Returned value is one of 0, 90, 180, 270. +int display_get_orientation(void); + +#ifdef XFRAMEBUFFER +// Provides pointer to the inactive (writeable) framebuffer. +// +// If framebuffer is not available yet due to display refreshing etc., +// the function may block until the buffer is ready to write. +void *display_get_frame_addr(void); + +#else // XFRAMEBUFFER + +// Waits for the vertical synchronization pulse. +// +// Used for synchronization with the display refresh cycle +// to achieve tearless UX if possible when not using a frame buffer. +void display_wait_for_sync(void); +#endif + +// Swaps the frame buffers +// +// The function waits for vertical synchronization and +// swaps the active (currently displayed) and the inactive frame buffers. +void display_refresh(void); + +// +void display_set_compatible_settings(void); + +// Functions for drawing on the display +// Fills a rectangle with a specified color +void display_fill(const dma2d_params_t *dp); + +// Copies an RGB565 bitmap to a specified rectangle +void display_copy_rgb565(const dma2d_params_t *dp); + +// Copies a MONO4 bitmap to a specified rectangle +void display_copy_mono4(const dma2d_params_t *dp); + +// Copies a MONO1P bitmap to a specified rectangle +void display_copy_mono1p(const dma2d_params_t *dp); + +// Save the screen content to a file. +// +// The function is available only on the emulator +const char *display_save(const char *prefix); +void display_clear_save(void); + +#include "xdisplay_legacy.h" + +#endif // TREZORHAL_XDISPLAY_H \ No newline at end of file diff --git a/core/embed/trezorhal/xdisplay_legacy.c b/core/embed/trezorhal/xdisplay_legacy.c new file mode 100644 index 000000000..3725cdda3 --- /dev/null +++ b/core/embed/trezorhal/xdisplay_legacy.c @@ -0,0 +1,50 @@ +#include "xdisplay_legacy.h" +#include "xdisplay.h" + +int display_orientation(int angle) { + if (angle >= 0) { + return display_set_orientation(angle); + } else { + return display_get_orientation(); + } +} + +int display_backlight(int level) { + if (level >= 0) { + return display_set_backlight(level); + } else { + return display_get_backlight(); + } +} + +void display_shift_window(uint16_t pixels){}; + +uint16_t display_get_window_offset(void) { return 0; } + +void display_pixeldata_dirty(void) {} + +uint8_t *display_get_wr_addr(void) { return (uint8_t *)0; } + +void display_sync(void) {} + +void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {} + +void display_pixeldata(uint16_t c) {} + +uint32_t *display_get_fb_addr(void) { +#ifdef XFRAMEBUFFER + return (uint32_t *)display_get_frame_addr(); +#else + return (uint32_t *)0; +#endif +} + +void display_offset(int set_xy[2], int *get_x, int *get_y) { + *get_x = 0; + *get_y = 0; +} + +void display_clear(void) {} + +void display_text_render_buffer(const char *text, int textlen, int font, + buffer_text_t *buffer, int text_offset) {} diff --git a/core/embed/trezorhal/xdisplay_legacy.h b/core/embed/trezorhal/xdisplay_legacy.h new file mode 100644 index 000000000..8e330fb9d --- /dev/null +++ b/core/embed/trezorhal/xdisplay_legacy.h @@ -0,0 +1,34 @@ + +#ifndef TREZORHAL_DISPLAY_LEGACY_H +#define TREZORHAL_DISPLAY_LEGACY_H + +#include +#include + +#define DISPLAY_FRAMEBUFFER_WIDTH 768 +#define DISPLAY_FRAMEBUFFER_HEIGHT 480 +#define DISPLAY_FRAMEBUFFER_OFFSET_X 0 +#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0 + +// Functions emulating legacy API +// + +int display_orientation(int angle); +int display_backlight(int level); +void display_refresh(void); +void display_shift_window(uint16_t pixels); +uint16_t display_get_window_offset(void); +void display_pixeldata_dirty(void); +uint8_t* display_get_wr_addr(void); +void display_sync(void); +void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); +void display_pixeldata(uint16_t c); +uint32_t* display_get_fb_addr(void); + +void display_clear(void); +void display_text_render_buffer(const char* text, int textlen, int font, + buffer_text_t* buffer, int text_offset); + +#define PIXELDATA(c) display_pixeldata(c) + +#endif // TREZORHAL_DISPLAY_LEGACY_H diff --git a/core/site_scons/boards/discovery.py b/core/site_scons/boards/discovery.py index 8f0738429..b5d39ec64 100644 --- a/core/site_scons/boards/discovery.py +++ b/core/site_scons/boards/discovery.py @@ -36,9 +36,20 @@ def configure( sources += [ "embed/models/model_D001_layout.c", ] - sources += [f"embed/trezorhal/stm32f4/displays/{display}"] - sources += ["embed/trezorhal/stm32f4/displays/ili9341_spi.c"] + + if "new_rendering" in features_wanted: + sources += [ + "embed/trezorhal/xdisplay_legacy.c", + "embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c", + "embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c", + "embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c", + ] + else: + sources += [f"embed/trezorhal/stm32f4/displays/{display}"] + sources += ["embed/trezorhal/stm32f4/displays/ili9341_spi.c"] + sources += ["embed/trezorhal/stm32f4/dma2d.c"] + sources += ["embed/trezorhal/stm32f4/dma2d_gl.c"] sources += [ "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma2d.c" ] @@ -51,6 +62,11 @@ def configure( features_available.append("dma2d") features_available.append("framebuffer") + if "new_rendering" in features_wanted: + defines += ["XFRAMEBUFFER"] + features_available.append("xframebuffer") + features_available.append("display_rgb565") + if "input" in features_wanted: sources += ["embed/trezorhal/stm32f4/i2c.c"] sources += ["embed/trezorhal/stm32f4/touch/stmpe811.c"] @@ -71,4 +87,10 @@ def configure( env.get("ENV")["TREZOR_BOARD"] = board env.get("ENV")["MCU_TYPE"] = mcu + rust_defs = env.get("ENV")["RUST_INCLUDES"] + rust_defs += "-DFRAMEBUFFER;" + if "new_rendering" in features_wanted: + rust_defs += "-DXFRAMEBUFFER;" + env.get("ENV")["RUST_INCLUDES"] = rust_defs + return features_available diff --git a/core/site_scons/boards/discovery2.py b/core/site_scons/boards/discovery2.py index 5a7c2d32a..453b50f20 100644 --- a/core/site_scons/boards/discovery2.py +++ b/core/site_scons/boards/discovery2.py @@ -43,9 +43,18 @@ def configure( sources += [ "embed/models/model_D002_layout.c", ] - sources += [ - f"embed/trezorhal/stm32u5/displays/{display}", - ] + + if "new_rendering" in features_wanted: + sources += [ + "embed/trezorhal/xdisplay_legacy.c", + "embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c", + "embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c", + "embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c", + ] + else: + sources += [ + f"embed/trezorhal/stm32u5/displays/{display}", + ] if "input" in features_wanted: sources += [ @@ -85,11 +94,16 @@ def configure( defines += ["USE_DMA2D", "FRAMEBUFFER", "FRAMEBUFFER32BIT"] sources += [ "embed/trezorhal/stm32u5/dma2d.c", + "embed/trezorhal/stm32u5/dma2d_gl.c", ] features_available.append("dma2d") features_available.append("framebuffer") features_available.append("framebuffer32bit") + if "new_rendering" in features_wanted: + features_available.append("xframebuffer") + features_available.append("display_rgba8888") + env.get("ENV")["TREZOR_BOARD"] = board env.get("ENV")["MCU_TYPE"] = mcu env.get("ENV")["LINKER_SCRIPT"] = linker_script @@ -97,4 +111,10 @@ def configure( defs = env.get("CPPDEFINES_IMPLICIT") defs += ["__ARM_FEATURE_CMSE=3"] + rust_defs = env.get("ENV")["RUST_INCLUDES"] + rust_defs += "-DFRAMEBUFFER;" + if "new_rendering" in features_wanted: + rust_defs += "-DXFRAMEBUFFER;" + env.get("ENV")["RUST_INCLUDES"] = rust_defs + return features_available diff --git a/core/site_scons/boards/trezor_r_v10.py b/core/site_scons/boards/trezor_r_v10.py index 3abe63aec..566c1412d 100644 --- a/core/site_scons/boards/trezor_r_v10.py +++ b/core/site_scons/boards/trezor_r_v10.py @@ -17,6 +17,11 @@ def configure( board = "trezor_r_v10.h" display = "vg-2864ksweg01.c" + if "new_rendering" in features_wanted: + defines += ["XFRAMEBUFFER"] + features_available.append("xframebuffer") + features_available.append("display_mono") + mcu = "STM32F427xx" stm32f4_common_files(env, defines, sources, paths) @@ -36,7 +41,12 @@ def configure( sources += [ "embed/models/model_T2B1_layout.c", ] - sources += [f"embed/trezorhal/stm32f4/displays/{display}"] + + if "new_rendering" in features_wanted: + sources += ["embed/trezorhal/xdisplay_legacy.c"] + sources += ["embed/trezorhal/stm32f4/display/vg-2864/display_driver.c"] + else: + sources += [f"embed/trezorhal/stm32f4/displays/{display}"] sources += ["embed/trezorhal/stm32f4/i2c.c"] @@ -77,4 +87,9 @@ def configure( env.get("ENV")["TREZOR_BOARD"] = board env.get("ENV")["MCU_TYPE"] = mcu + if "new_rendering" in features_wanted: + rust_defs = env.get("ENV")["RUST_INCLUDES"] + rust_defs += "-DXFRAMEBUFFER;" + env.get("ENV")["RUST_INCLUDES"] = rust_defs + return features_available diff --git a/core/site_scons/boards/trezor_r_v3.py b/core/site_scons/boards/trezor_r_v3.py index 25e2c9dec..f2565ede1 100644 --- a/core/site_scons/boards/trezor_r_v3.py +++ b/core/site_scons/boards/trezor_r_v3.py @@ -17,6 +17,11 @@ def configure( board = "trezor_r_v3.h" display = "ug-2828tswig01.c" + if "new_rendering" in features_wanted: + defines += ["XFRAMEBUFFER"] + features_available.append("xframebuffer") + features_available.append("display_mono") + mcu = "STM32F427xx" stm32f4_common_files(env, defines, sources, paths) @@ -36,7 +41,12 @@ def configure( sources += [ "embed/models/model_T2B1_layout.c", ] - sources += [f"embed/trezorhal/stm32f4/displays/{display}"] + + if "new_rendering" in features_wanted: + sources += ["embed/trezorhal/xdisplay_legacy.c"] + sources += ["embed/trezorhal/stm32f4/display/ug-2828/display_driver.c"] + else: + sources += [f"embed/trezorhal/stm32f4/displays/{display}"] if "input" in features_wanted: sources += ["embed/trezorhal/stm32f4/button.c"] @@ -64,4 +74,9 @@ def configure( env.get("ENV")["TREZOR_BOARD"] = board env.get("ENV")["MCU_TYPE"] = mcu + if "new_rendering" in features_wanted: + rust_defs = env.get("ENV")["RUST_INCLUDES"] + rust_defs += "-DXFRAMEBUFFER;" + env.get("ENV")["RUST_INCLUDES"] = rust_defs + return features_available diff --git a/core/site_scons/boards/trezor_r_v4.py b/core/site_scons/boards/trezor_r_v4.py index 63dab36fc..e3461e5ee 100644 --- a/core/site_scons/boards/trezor_r_v4.py +++ b/core/site_scons/boards/trezor_r_v4.py @@ -17,6 +17,11 @@ def configure( board = "trezor_r_v4.h" display = "vg-2864ksweg01.c" + if "new_rendering" in features_wanted: + defines += ["XFRAMEBUFFER"] + features_available.append("xframebuffer") + features_available.append("display_mono") + mcu = "STM32F427xx" stm32f4_common_files(env, defines, sources, paths) @@ -36,7 +41,12 @@ def configure( sources += [ "embed/models/model_T2B1_layout.c", ] - sources += [f"embed/trezorhal/stm32f4/displays/{display}"] + + if "new_rendering" in features_wanted: + sources += ["embed/trezorhal/xdisplay_legacy.c"] + sources += ["embed/trezorhal/stm32f4/display/vg-2864/display_driver.c"] + else: + sources += [f"embed/trezorhal/stm32f4/displays/{display}"] if "input" in features_wanted: sources += ["embed/trezorhal/stm32f4/button.c"] @@ -60,4 +70,9 @@ def configure( env.get("ENV")["TREZOR_BOARD"] = board env.get("ENV")["MCU_TYPE"] = mcu + if "new_rendering" in features_wanted: + rust_defs = env.get("ENV")["RUST_INCLUDES"] + rust_defs += "-DXFRAMEBUFFER;" + env.get("ENV")["RUST_INCLUDES"] = rust_defs + return features_available diff --git a/core/site_scons/boards/trezor_r_v6.py b/core/site_scons/boards/trezor_r_v6.py index 6fe8f3044..3444c4bb1 100644 --- a/core/site_scons/boards/trezor_r_v6.py +++ b/core/site_scons/boards/trezor_r_v6.py @@ -17,6 +17,11 @@ def configure( board = "trezor_r_v6.h" display = "vg-2864ksweg01.c" + if "new_rendering" in features_wanted: + defines += ["XFRAMEBUFFER"] + features_available.append("xframebuffer") + features_available.append("display_mono") + mcu = "STM32F427xx" stm32f4_common_files(env, defines, sources, paths) @@ -36,7 +41,12 @@ def configure( sources += [ "embed/models/model_T2B1_layout.c", ] - sources += [f"embed/trezorhal/stm32f4/displays/{display}"] + + if "new_rendering" in features_wanted: + sources += ["embed/trezorhal/xdisplay_legacy.c"] + sources += ["embed/trezorhal/stm32f4/display/vg-2864/display_driver.c"] + else: + sources += [f"embed/trezorhal/stm32f4/displays/{display}"] if "input" in features_wanted: sources += ["embed/trezorhal/stm32f4/button.c"] @@ -60,4 +70,9 @@ def configure( env.get("ENV")["TREZOR_BOARD"] = board env.get("ENV")["MCU_TYPE"] = mcu + if "new_rendering" in features_wanted: + rust_defs = env.get("ENV")["RUST_INCLUDES"] + rust_defs += "-DXFRAMEBUFFER;" + env.get("ENV")["RUST_INCLUDES"] = rust_defs + return features_available diff --git a/core/site_scons/boards/trezor_t.py b/core/site_scons/boards/trezor_t.py index b53cd2c45..84bc0a69e 100644 --- a/core/site_scons/boards/trezor_t.py +++ b/core/site_scons/boards/trezor_t.py @@ -18,6 +18,9 @@ def configure( hw_revision = 0 features_available.append("disp_i8080_8bit_dw") + if "new_rendering" in features_wanted: + features_available.append("display_rgb565") + mcu = "STM32F427xx" stm32f4_common_files(env, defines, sources, paths) @@ -37,20 +40,41 @@ def configure( sources += [ "embed/models/model_T2T1_layout.c", ] - sources += [f"embed/trezorhal/stm32f4/displays/{display}"] + if "new_rendering" in features_wanted: + sources += ["embed/trezorhal/xdisplay_legacy.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_fb.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_driver.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_io.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_panel.c"] + sources += [ + "embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c", + ] + sources += [ + "embed/trezorhal/stm32f4/display/st-7789/panels/154a.c", + ] + sources += [ + "embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c", + ] + sources += [ + "embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c", + ] + + else: + sources += [f"embed/trezorhal/stm32f4/displays/{display}"] + sources += [ + "embed/trezorhal/stm32f4/displays/panels/tf15411a.c", + ] + sources += [ + "embed/trezorhal/stm32f4/displays/panels/154a.c", + ] + sources += [ + "embed/trezorhal/stm32f4/displays/panels/lx154a2411.c", + ] + sources += [ + "embed/trezorhal/stm32f4/displays/panels/lx154a2422.c", + ] + sources += ["embed/trezorhal/stm32f4/backlight_pwm.c"] - sources += [ - "embed/trezorhal/stm32f4/displays/panels/tf15411a.c", - ] - sources += [ - "embed/trezorhal/stm32f4/displays/panels/154a.c", - ] - sources += [ - "embed/trezorhal/stm32f4/displays/panels/lx154a2411.c", - ] - sources += [ - "embed/trezorhal/stm32f4/displays/panels/lx154a2422.c", - ] features_available.append("backlight") @@ -87,7 +111,7 @@ def configure( if "dma2d" in features_wanted: defines += ["USE_DMA2D"] sources += ["embed/trezorhal/stm32f4/dma2d.c"] - sources += ["embed/trezorhal/stm32f4/dma2d_gdc.c"] + sources += ["embed/trezorhal/stm32f4/dma2d_gl.c"] sources += [ "vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma2d.c" ] diff --git a/core/site_scons/boards/trezor_t3t1_revE.py b/core/site_scons/boards/trezor_t3t1_revE.py index 2d6d2291d..b79428f43 100644 --- a/core/site_scons/boards/trezor_t3t1_revE.py +++ b/core/site_scons/boards/trezor_t3t1_revE.py @@ -20,6 +20,11 @@ def configure( features_available.append("framebuffer") defines += ["FRAMEBUFFER"] + if "new_rendering" in features_wanted: + features_available.append("xframebuffer") + features_available.append("display_rgb565") + defines += ["XFRAMEBUFFER"] + mcu = "STM32U585xx" linker_script = "stm32u58" @@ -40,11 +45,23 @@ def configure( sources += [ "embed/models/model_T3T1_layout.c", ] - sources += [f"embed/trezorhal/stm32u5/displays/{display}"] + + if "new_rendering" in features_wanted: + sources += ["embed/trezorhal/xdisplay_legacy.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_fb.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_driver.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_io.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_panel.c"] + sources += [ + "embed/trezorhal/stm32u5/display/st-7789/panels/lx154a2422.c", + ] + else: + sources += [f"embed/trezorhal/stm32u5/displays/{display}"] + sources += [ + "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c", + ] + sources += ["embed/trezorhal/stm32u5/backlight_pwm.c"] - sources += [ - "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c", - ] env_constraints = env.get("CONSTRAINTS") if not (env_constraints and "limited_util_s" in env_constraints): @@ -94,6 +111,7 @@ def configure( if "dma2d" in features_wanted: defines += ["USE_DMA2D"] sources += ["embed/trezorhal/stm32u5/dma2d.c"] + sources += ["embed/trezorhal/stm32u5/dma2d_gl.c"] features_available.append("dma2d") if "optiga" in features_wanted: @@ -114,6 +132,8 @@ def configure( rust_defs = env.get("ENV")["RUST_INCLUDES"] rust_defs += "-DFRAMEBUFFER;" + if "new_rendering" in features_wanted: + rust_defs += "-DXFRAMEBUFFER;" env.get("ENV")["RUST_INCLUDES"] = rust_defs return features_available diff --git a/core/site_scons/boards/trezor_t3t1_v4.py b/core/site_scons/boards/trezor_t3t1_v4.py index 7d66720da..a8f68a3e7 100644 --- a/core/site_scons/boards/trezor_t3t1_v4.py +++ b/core/site_scons/boards/trezor_t3t1_v4.py @@ -20,6 +20,11 @@ def configure( features_available.append("framebuffer") defines += ["FRAMEBUFFER"] + if "new_rendering" in features_wanted: + features_available.append("xframebuffer") + features_available.append("display_rgb565") + defines += ["XFRAMEBUFFER"] + mcu = "STM32U585xx" linker_script = "stm32u58" @@ -41,10 +46,24 @@ def configure( "embed/models/model_T3T1_layout.c", ] sources += [f"embed/trezorhal/stm32u5/displays/{display}"] + + if "new_rendering" in features_wanted: + sources += ["embed/trezorhal/xdisplay_legacy.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_fb.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_driver.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_io.c"] + sources += ["embed/trezorhal/stm32f4/display/st-7789/display_panel.c"] + sources += [ + "embed/trezorhal/stm32u5/display/st-7789/panels/lx154a2422.c", + ] + + else: + sources += [f"embed/trezorhal/stm32u5/displays/{display}"] + sources += [ + "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c", + ] + sources += ["embed/trezorhal/stm32u5/backlight_pwm.c"] - sources += [ - "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c", - ] env_constraints = env.get("CONSTRAINTS") if not (env_constraints and "limited_util_s" in env_constraints): @@ -94,6 +113,7 @@ def configure( if "dma2d" in features_wanted: defines += ["USE_DMA2D"] sources += ["embed/trezorhal/stm32u5/dma2d.c"] + sources += ["embed/trezorhal/stm32u5/dma2d_gl.c"] features_available.append("dma2d") if "optiga" in features_wanted: @@ -114,6 +134,8 @@ def configure( rust_defs = env.get("ENV")["RUST_INCLUDES"] rust_defs += "-DFRAMEBUFFER;" + if "new_rendering" in features_wanted: + rust_defs += "-DXFRAMEBUFFER;" env.get("ENV")["RUST_INCLUDES"] = rust_defs return features_available