feat(core): refactor display drivers

[no changelog]
obrusvit/ui-t3t1-reset-device-apple-hotfix
cepetr 4 weeks ago
parent a47ae5da1a
commit f085c50931

@ -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)

@ -5,6 +5,7 @@ import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1'
if TREZOR_MODEL in ('1', ):
# skip boardloader build
@ -20,6 +21,9 @@ if TREZOR_MODEL in ('1', ):
FEATURES_WANTED = ["sd_card"]
if NEW_RENDERING:
FEATURES_WANTED.append("new_rendering")
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = ["BOARDLOADER"]
@ -60,13 +64,27 @@ CPPPATH_MOD += [
SOURCE_MOD += [
'embed/lib/colors.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_bitblt_rgb565.c',
'embed/lib/gl_bitblt_rgba8888.c',
'embed/lib/gl_bitblt_mono8.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',
'embed/lib/terminal.c',
]
if NEW_RENDERING:
CPPDEFINES_MOD += ['NEW_RENDERING']
SOURCE_MOD += [
'embed/lib/gl_draw.c',
]
else:
SOURCE_MOD += [
'embed/lib/display_draw.c',
]
env = Environment(ENV=os.environ,
CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')),

@ -7,6 +7,7 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
BOOTLOADER_QA = ARGUMENTS.get('BOOTLOADER_QA', '0') == '1'
PRODUCTION = 0 if BOOTLOADER_QA else ARGUMENTS.get('PRODUCTION', '0') == '1'
NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1'
if TREZOR_MODEL in ('1', ):
# skip bootloader build
@ -22,6 +23,9 @@ if TREZOR_MODEL in ('1', ):
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "dma2d"]
if NEW_RENDERING:
FEATURES_WANTED.append("new_rendering")
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
@ -90,9 +94,12 @@ SOURCE_MOD += [
'embed/lib/buffers.c',
'embed/lib/colors.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_bitblt_mono8.c',
'embed/lib/gl_bitblt_rgb565.c',
'embed/lib/gl_bitblt_rgba8888.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',
'embed/lib/terminal.c',
@ -102,6 +109,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',
]
SOURCE_NANOPB = [
'vendor/nanopb/pb_common.c',
'vendor/nanopb/pb_decode.c',
@ -228,6 +246,12 @@ def cargo_build():
features.append("bootloader")
features.extend(FEATURES_AVAILABLE)
if NEW_RENDERING:
features.append('new_rendering')
if TREZOR_MODEL in ('T',):
features.append('ui_antialiasing')
cargo_opts = [
f'--target={env.get("ENV")["RUST_TARGET"]}',
f'--target-dir=../../build/bootloader/rust',

@ -5,6 +5,7 @@ import tools
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1'
if TREZOR_MODEL in ('1', 'DISC1', 'DISC2'):
# skip bootloader_ci build
@ -82,8 +83,8 @@ CPPPATH_MOD += [
SOURCE_MOD += [
'embed/extmod/modtrezorcrypto/rand.c',
'embed/lib/colors.c',
'embed/lib/display_draw.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/image.c',

@ -6,6 +6,7 @@ import boards
TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1'
DMA2D = False
if TREZOR_MODEL in ('1', 'DISC1'):
@ -22,6 +23,9 @@ if TREZOR_MODEL in ('1', 'DISC1'):
FEATURES_WANTED = ["input", "rgb_led", "dma2d"]
if NEW_RENDERING:
FEATURES_WANTED.append("new_rendering")
CCFLAGS_MOD = ''
CPPPATH_MOD = []
CPPDEFINES_MOD = []
@ -87,10 +91,13 @@ SOURCE_MOD += [
'embed/lib/buffers.c',
'embed/lib/colors.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/dma2d_emul.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_bitblt_mono8.c',
'embed/lib/gl_bitblt_rgb565.c',
'embed/lib/gl_bitblt_rgba8888.c',
'embed/lib/image.c',
'embed/lib/terminal.c',
'embed/lib/touch.c',
@ -101,6 +108,22 @@ SOURCE_MOD += [
'vendor/trezor-storage/flash_area.c',
]
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']
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',
@ -135,7 +158,6 @@ SOURCE_BOOTLOADER = [
SOURCE_TREZORHAL = [
'embed/trezorhal/unix/boot_args.c',
'embed/trezorhal/unix/display-unix.c',
'embed/trezorhal/unix/fault_handlers.c',
'embed/trezorhal/unix/flash.c',
'embed/trezorhal/unix/flash_otp.c',
@ -147,6 +169,17 @@ SOURCE_TREZORHAL = [
'embed/trezorhal/unix/secret.c',
]
if NEW_RENDERING:
SOURCE_TREZORHAL += [
'embed/trezorhal/unix/display_driver.c',
'embed/trezorhal/unix/dma2d_bitblt.c',
'embed/trezorhal/xdisplay_legacy.c',
]
else:
SOURCE_TREZORHAL += [
'embed/trezorhal/unix/display-unix.c',
]
if TREZOR_MODEL in ('R', 'T3T1'):
SOURCE_TREZORHAL += [
'embed/trezorhal/unix/optiga_hal.c',
@ -260,17 +293,18 @@ cmake_gen = env.Command(
#
RUST_TARGET = 'x86_64-unknown-linux-gnu'
RUST_PROFILE = 'release'
RUST_LIB = 'trezor_lib'
RUST_LIBDIR = f'build/bootloader_emu/rust/{RUST_TARGET}/{RUST_PROFILE}'
if ARGUMENTS.get('TREZOR_EMULATOR_DEBUGGABLE', '0') == '1':
RUST_PROFILE = 'dev'
RUST_LIBDIR = f'build/bootloader_emu/rust/{RUST_TARGET}/debug'
else:
RUST_PROFILE = 'release'
RUST_LIBDIR = f'build/bootloader_emu/rust/{RUST_TARGET}/release'
RUST_LIBPATH = f'{RUST_LIBDIR}/lib{RUST_LIB}.a'
def cargo_build():
# Determine the profile build flags.
if RUST_PROFILE == 'release':
profile = '--release'
else:
profile = ''
if TREZOR_MODEL in ("1",):
features = ["model_t1"]
elif TREZOR_MODEL in ("R",):
@ -280,6 +314,19 @@ def cargo_build():
else:
features = ["model_tt"]
if NEW_RENDERING:
features.append('new_rendering')
if TREZOR_MODEL in ('T',):
features.append('display_rgb565')
features.append('ui_antialiasing')
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')
features.append('ui_antialiasing')
if TREZOR_MODEL in ('T', 'T3T1'):
features.append('touch')
features.append('backlight')
@ -299,7 +346,7 @@ def cargo_build():
'-Z build-std-features=panic_immediate_abort',
]
return f'cd embed/rust; cargo build {profile} ' + ' '.join(cargo_opts)
return f'cd embed/rust; cargo build --profile {RUST_PROFILE} ' + ' '.join(cargo_opts)
rust = env.Command(
target=RUST_LIBPATH,

@ -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 = {
@ -25,6 +26,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 = []
@ -203,9 +206,12 @@ SOURCE_MOD += [
'embed/lib/buffers.c',
'embed/lib/colors.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_bitblt_rgb565.c',
'embed/lib/gl_bitblt_rgba8888.c',
'embed/lib/gl_bitblt_mono8.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',
'embed/lib/terminal.c',
@ -216,6 +222,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',
@ -744,8 +761,17 @@ def cargo_build():
features.append('universal_fw')
features.append('ui')
features.append('translations')
if NEW_RENDERING:
features.append('new_rendering')
if PYOPT == '0':
features.append('debug')
features.append('ui_debug')
if TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'):
features.append('ui_antialiasing')
features.append('ui_blurring')
features.append('ui_jpeg_decoder')
features.extend(FEATURES_AVAILABLE)

@ -81,8 +81,8 @@ CPPPATH_MOD += [
SOURCE_MOD += [
'embed/lib/colors.c',
'embed/lib/display_draw.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/image.c',

@ -55,8 +55,8 @@ CPPPATH_MOD += [
]
SOURCE_MOD += [
'embed/lib/colors.c',
'embed/lib/display_draw.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/image.c',

@ -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
@ -205,9 +206,12 @@ SOURCE_MOD += [
'embed/lib/buffers.c',
'embed/lib/colors.c',
'embed/lib/display_utils.c',
'embed/lib/display.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
'embed/lib/gl_color.c',
'embed/lib/gl_bitblt_rgb565.c',
'embed/lib/gl_bitblt_rgba8888.c',
'embed/lib/gl_bitblt_mono8.c',
'embed/lib/image.c',
'embed/lib/terminal.c',
'embed/lib/translations.c',
@ -217,6 +221,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',
@ -250,6 +264,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',
@ -394,7 +419,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',
@ -410,6 +434,19 @@ 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/unix/dma2d_bitblt.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',
@ -424,6 +461,7 @@ if DMA2D:
CPPDEFINES_MOD += [
'USE_DMA2D',
]
SOURCE_UNIX += [
'embed/lib/dma2d_emul.c',
]
@ -839,9 +877,24 @@ def cargo_build():
if TREZOR_MODEL in ('T', 'T3T1'):
features.append('touch')
features.append('sd_card')
features.append('ui_antialiasing')
features.append('ui_blurring')
features.append('ui_jpeg_decoder')
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}'

@ -21,9 +21,11 @@
#include TREZOR_BOARD
#include "board_capabilities.h"
#include "buffers.h"
#include "common.h"
#include "compiler_traits.h"
#include "display.h"
#include "display_draw.h"
#include "fault_handlers.h"
#include "flash.h"
#include "image.h"

@ -78,6 +78,8 @@ SECTIONS {
.buf : ALIGN(4) {
*(.buf*);
. = ALIGN(4);
*(.no_dma_buffers*);
. = ALIGN(4);
} >SRAM1
.stack : ALIGN(8) {

@ -78,6 +78,8 @@ SECTIONS {
.buf : ALIGN(4) {
*(.buf*);
. = ALIGN(4);
*(.no_dma_buffers*);
. = ALIGN(4);
} >SRAM1
.stack : ALIGN(8) {

@ -21,6 +21,7 @@
#include "bootui.h"
#include "display.h"
#include "display_draw.h"
#include "display_utils.h"
#include "icon_done.h"
#include "icon_fail.h"

@ -22,6 +22,7 @@
#include "common.h"
#include "display.h"
#include "display_draw.h"
#include "flash.h"
#include "flash_otp.h"
#include "image.h"

@ -73,4 +73,10 @@ SECTIONS {
*(.boot_args*);
. = ALIGN(8);
} >BOOT_ARGS
.data_ccm : ALIGN(4) {
*(.no_dma_buffers*);
. = ALIGN(4);
} >CCMRAM
}

@ -18,6 +18,8 @@
*/
#include "display.h"
#include "display_draw.h"
#include "fonts/fonts.h"
/// class Display:
/// """
@ -128,11 +130,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_backlight_obj,
/// Saves current display contents to PNG file with given prefix.
/// """
STATIC mp_obj_t mod_trezorui_Display_save(mp_obj_t self, mp_obj_t prefix) {
#ifdef TREZOR_EMULATOR
mp_buffer_info_t pfx = {0};
mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ);
if (pfx.len > 0) {
display_save(pfx.buf);
}
#endif
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_save_obj,
@ -143,7 +147,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_save_obj,
/// Clears buffers in display saving.
/// """
STATIC mp_obj_t mod_trezorui_Display_clear_save(mp_obj_t self) {
#ifdef TREZOR_EMULATOR
display_clear_save();
#endif
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_clear_save_obj,

@ -89,6 +89,8 @@ SECTIONS {
.data_ccm : ALIGN(4) {
*(.no_dma_buffers*);
. = ALIGN(4);
*(.buf*);
. = ALIGN(4);
} >SRAM1
.heap : ALIGN(4) {

@ -87,6 +87,11 @@ SECTIONS {
. = ALIGN(4);
} >SRAM
.buf : ALIGN(4) {
*(.buf*);
. = ALIGN(4);
} >SRAM
.heap : ALIGN(4) {
. = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */
. = ABSOLUTE(sram_end); /* this explicitly sets the end of the heap */

@ -19,7 +19,7 @@
#define _GNU_SOURCE
#include "display.h"
#include "display_draw.h"
#include "buffers.h"
#include "common.h"
@ -34,7 +34,7 @@
#include "memzero.h"
#include "display_interface.h"
#include "display.h"
static struct { int x, y; } DISPLAY_OFFSET;
@ -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);
}

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DISPLAY_H__
#define __DISPLAY_H__
#ifndef __DISPLAY_DRAW_H__
#define __DISPLAY_DRAW_H__
#include <stdbool.h>
#include <stddef.h>
@ -27,7 +27,6 @@
#include "buffers.h"
#include "colors.h"
#include TREZOR_BOARD
#include "display_interface.h"
#include "fonts/fonts.h"
// provided by common

@ -18,7 +18,9 @@
*/
#include "colors.h"
#include "display_interface.h"
#include "display.h"
#ifndef NEW_RENDERING
typedef enum {
DMA2D_LAYER_FG = 1,
@ -142,3 +144,5 @@ void dma2d_start_blend(uint8_t* overlay_addr, uint8_t* bg_addr,
void dma2d_wait_for_transfer(void) {
// done in place when emulating, so no need for wait here
}
#endif

@ -0,0 +1,120 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GL_BITBLT_H
#define GL_BITBLT_H
#include <stdbool.h>
#include <stdint.h>
#include "gl_color.h"
// These module provides provides low-level bit block transfer (bitblt)
// operations on different bitmap/framebuffer types.
//
// `fill` - fills a rectangle with a solid color (with an optional
// alpha, allowing color blending).
//
// `copy` - copies a bitmap or part of it to the destination bitmap.
//
// `blend` - blends a bitmap with a 1- or 4-bit alpha channel to the
// destination using background and foreground colors.
//
// These operations might be accelerated using DMA2D (ChromART accelerator)
// on the STM32 platform.
// Represents a set of parameters for a bit block transfer operation.
typedef struct {
// Pointer to the destination bitmap's first row
void* dst_row;
// Number of bytes per line in the destination bitmap
uint16_t dst_stride;
// X-coordinate of the top-left corner inside the destination
uint16_t dst_x;
// Y-coordinate of the top-left corner inside the destination
uint16_t dst_y;
// Height of the filled/copied/blended area
uint16_t height;
// Width of the filled/copied/blended area
uint16_t width;
// Pointer to the source bitmap's first row
// (unused for fill operations)
void* src_row;
// Number of bytes per line in the source bitmap
// (unused for fill operations)
uint16_t src_stride;
// X-coordinate of the origin in the source bitmap
// (unused for fill operations)
uint16_t src_x;
// Y-coordinate of the origin in the source bitmap
// (unused for fill operations)
uint16_t src_y;
// Foreground color used when copying/blending/filling
gl_color_t src_fg;
// Background color used when copying mono bitmaps
gl_color_t src_bg;
// Alpha value for fill operation (255 => normal fill, 0 => noop)
uint8_t src_alpha;
} gl_bitblt_t;
// Functions for RGB565 bitmap/framebuffer
// Fills a rectangle with a solid color
void gl_rgb565_fill(const gl_bitblt_t* bb);
// Copies a mono bitmap (with 1-bit alpha channel)
void gl_rgb565_copy_mono1p(const gl_bitblt_t* bb);
// Copies a mono bitmap (with 4-bit alpha channel)
void gl_rgb565_copy_mono4(const gl_bitblt_t* bb);
// Copies an RGB565 bitmap
void gl_rgb565_copy_rgb565(const gl_bitblt_t* bb);
// Blends a mono bitmap (with 4-bit alpha channel)
// with the destination bitmap
void gl_rgb565_blend_mono4(const gl_bitblt_t* bb);
// Functions for RGBA8888 bitmap/framebuffer
void gl_rgba8888_fill(const gl_bitblt_t* bb);
// Copies a mono bitmap (with 1-bit alpha channel)
void gl_rgba8888_copy_mono1p(const gl_bitblt_t* bb);
// Copies a mono bitmap (with 4-bit alpha channel)
void gl_rgba8888_copy_mono4(const gl_bitblt_t* bb);
// Copies an RGB565 bitmap
void gl_rgba8888_copy_rgb565(const gl_bitblt_t* bb);
// Copies an RGBA8888 bitmap
void gl_rgba8888_copy_rgba8888(const gl_bitblt_t* bb);
// Blends a mono bitmap (with 4-bit alpha channel)
// with the destination bitmap
void gl_rgba8888_blend_mono4(const gl_bitblt_t* bb);
// Functions for Mono8 bitmap/framebuffer
void gl_mono8_fill(const gl_bitblt_t* bb);
// Copies a mono bitmap (with 1-bit alpha channel)
void gl_mono8_copy_mono1p(const gl_bitblt_t* bb);
// Copies a mono bitmap (with 4-bit alpha channel)
void gl_mono8_copy_mono4(const gl_bitblt_t* bb);
// Blends a mono bitmap (with 1-bit alpha channel)
// with the destination bitmap
void gl_mono8_blend_mono1p(const gl_bitblt_t* bb);
// Blends a mono bitmap (with 4-bit alpha channel)
// with the destination bitmap
void gl_mono8_blend_mono4(const gl_bitblt_t* bb);
#endif // GL_BITBLT_H

@ -0,0 +1,110 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "gl_bitblt.h"
void gl_mono8_fill(const gl_bitblt_t* bb) {
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
uint16_t height = bb->height;
uint8_t fg = gl_color_lum(bb->src_fg);
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = fg;
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
}
}
void gl_mono8_copy_mono1p(const gl_bitblt_t* bb) {
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
uint8_t* src = (uint8_t*)bb->src_row;
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
uint16_t height = bb->height;
uint8_t fg = gl_color_lum(bb->src_fg);
uint8_t bg = gl_color_lum(bb->src_bg);
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
uint8_t data = src[(src_ofs + x) / 8];
dst_ptr[x] = (data & mask) ? fg : bg;
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ofs += bb->src_stride;
}
}
void gl_mono8_copy_mono4(const gl_bitblt_t* bb) {
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
uint8_t* src_row = (uint8_t*)bb->src_row;
uint16_t height = bb->height;
uint8_t fg = gl_color_lum(bb->src_fg);
uint8_t bg = gl_color_lum(bb->src_bg);
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t src_data = src_row[(x + bb->src_x) / 2];
uint8_t src_lum = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0xF;
dst_ptr[x] = (fg * src_lum + bg * (15 - src_lum)) / 15;
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_row += bb->src_stride / sizeof(*src_row);
}
}
void gl_mono8_blend_mono1p(const gl_bitblt_t* bb) {
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
uint8_t* src = (uint8_t*)bb->src_row;
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
uint16_t height = bb->height;
uint8_t fg = gl_color_lum(bb->src_fg);
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
uint8_t data = src[(src_ofs + x) / 8];
dst_ptr[x] = (data & mask) ? fg : dst_ptr[x];
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ofs += bb->src_stride;
}
}
void gl_mono8_blend_mono4(const gl_bitblt_t* bb) {
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
uint8_t* src_row = (uint8_t*)bb->src_row;
uint16_t height = bb->height;
uint8_t fg = gl_color_lum(bb->src_fg);
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t src_data = src_row[(x + bb->src_x) / 2];
uint8_t src_alpha = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0x0F;
dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (15 - src_alpha)) / 15;
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_row += bb->src_stride / sizeof(*src_row);
}
}

@ -0,0 +1,144 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "gl_bitblt.h"
#if USE_DMA2D
#include "dma2d_bitblt.h"
#endif
void gl_rgb565_fill(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row)) {
dma2d_rgb565_fill(bb);
} else
#endif
{
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint16_t height = bb->height;
if (bb->src_alpha == 255) {
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = bb->src_fg;
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
}
} else {
uint8_t alpha = bb->src_alpha;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = gl_color16_blend_a8(bb->src_fg, dst_ptr[x], alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
}
}
}
}
void gl_rgb565_copy_mono1p(const gl_bitblt_t* bb) {
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint8_t* src = (uint8_t*)bb->src_row;
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
uint16_t height = bb->height;
uint16_t fg = gl_color_to_color16(bb->src_fg);
uint16_t bg = gl_color_to_color16(bb->src_bg);
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
uint8_t data = src[(src_ofs + x) / 8];
dst_ptr[x] = (data & mask) ? fg : bg;
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ofs += bb->src_stride;
}
}
void gl_rgb565_copy_mono4(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
dma2d_rgb565_copy_mono4(bb);
} else
#endif
{
const gl_color16_t* gradient =
gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint8_t* src_row = (uint8_t*)bb->src_row;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
dst_ptr[x] = gradient[fg_lum];
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_row += bb->src_stride / sizeof(*src_row);
}
}
}
void gl_rgb565_copy_rgb565(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
dma2d_rgb565_copy_rgb565(bb);
} else
#endif
{
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = src_ptr[x];
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
}
void gl_rgb565_blend_mono4(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
dma2d_rgb565_blend_mono4(bb);
} else
#endif
{
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint8_t* src_row = (uint8_t*)bb->src_row;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
dst_ptr[x] = gl_color16_blend_a4(
bb->src_fg, gl_color16_to_color(dst_ptr[x]), fg_alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_row += bb->src_stride / sizeof(*src_row);
}
}
}

@ -0,0 +1,166 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "gl_bitblt.h"
#if USE_DMA2D
#include "dma2d_bitblt.h"
#endif
void gl_rgba8888_fill(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row)) {
dma2d_rgba8888_fill(bb);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint16_t height = bb->height;
if (bb->src_alpha == 255) {
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = gl_color_to_color32(bb->src_fg);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
}
} else {
uint8_t alpha = bb->src_alpha;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = gl_color32_blend_a8(
bb->src_fg, gl_color32_to_color(dst_ptr[x]), alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
}
}
}
}
void gl_rgba8888_copy_mono1p(const gl_bitblt_t* bb) {
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint8_t* src = (uint8_t*)bb->src_row;
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
uint16_t height = bb->height;
uint32_t fg = gl_color_to_color32(bb->src_fg);
uint32_t bg = gl_color_to_color32(bb->src_bg);
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
uint8_t data = src[(src_ofs + x) / 8];
dst_ptr[x] = (data & mask) ? fg : bg;
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ofs += bb->src_stride;
}
}
void gl_rgba8888_copy_mono4(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
dma2d_rgba8888_copy_mono4(bb);
} else
#endif
{
const gl_color32_t* gradient =
gl_color32_gradient_a4(bb->src_fg, bb->src_bg);
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint8_t* src_row = (uint8_t*)bb->src_row;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
dst_ptr[x] = gradient[fg_lum];
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_row += bb->src_stride / sizeof(*src_row);
}
}
}
void gl_rgba8888_copy_rgb565(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
dma2d_rgba8888_copy_rgb565(bb);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = gl_color16_to_color32(src_ptr[x]);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
}
void gl_rgba8888_copy_rgba8888(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
dma2d_rgba8888_copy_rgba8888(bb);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint32_t* src_ptr = (uint32_t*)bb->src_row + bb->src_x;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = src_ptr[x];
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
}
void gl_rgba8888_blend_mono4(const gl_bitblt_t* bb) {
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
dma2d_rgba8888_blend_mono4(bb);
} else
#endif
{
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint8_t* src_row = (uint8_t*)bb->src_row;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
dst_ptr[x] = gl_color32_blend_a4(
bb->src_fg, gl_color32_to_color(dst_ptr[x]), fg_alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_row += bb->src_stride / sizeof(*src_row);
}
}
}

@ -0,0 +1,49 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "gl_color.h"
#include "colors.h"
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 (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] = gl_color16_blend_a4(fg_color, bg_color, alpha);
}
}
return (const gl_color16_t*)&cache[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 != gl_color32_to_color(cache[0]) ||
fg_color != gl_color32_to_color(cache[15])) {
for (int alpha = 0; alpha < 16; alpha++) {
cache[alpha] = gl_color32_blend_a4(fg_color, bg_color, alpha);
}
}
return (const gl_color32_t*)&cache[0];
}

@ -0,0 +1,308 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GL_COLOR_H
#define GL_COLOR_H
#include <stdint.h>
#define GL_COLOR_16BIT
// #define GL_COLOR_32BIT
// Color in RGB565 format
//
// |15 8 | 7 0|
// |---------------------------------|
// |r r r r r g g g | g g g b b b b b|
// |---------------------------------|
typedef uint16_t gl_color16_t;
// Color in RGBA8888 format
//
// |31 24 |23 16 |15 8 | 7 0 |
// |----------------------------------------------------------------------|
// |a a a a a a a a | r r r r r r r r | g g g g g g g g | b b b b b b b b |
// |----------------------------------------------------------------------|
//
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 "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 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 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 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;
r |= (r >> 5);
g |= (g >> 6);
b |= (b >> 5);
return (0xFFU << 24) | (r << 16) | (g << 8) | b;
}
// Converts 32-bit color to 16-bit color, alpha is ignored
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;
return r | g | b;
}
// Converts 16-bit color into luminance (ranging from 0 to 255)
static inline uint8_t gl_color16_lum(gl_color16_t color) {
uint32_t r = (color & 0xF800) >> 8;
uint32_t g = (color & 0x07E0) >> 3;
uint32_t b = (color & 0x001F) << 3;
r |= (r >> 5);
g |= (g >> 6);
b |= (b >> 5);
return (r + g + b) / 3;
}
#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 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;
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
uint16_t fg_g = (fg & 0x07E0) >> 5;
uint16_t bg_g = (bg & 0x07E0) >> 5;
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
uint16_t fg_b = (fg & 0x001F) >> 0;
uint16_t bg_b = (bg & 0x001F) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
return (r << 11) | (g << 5) | b;
}
// 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 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;
uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255;
uint16_t fg_g = (fg & 0x07E0) >> 5;
uint16_t bg_g = (bg & 0x07E0) >> 5;
uint16_t g = (fg_g * alpha + (bg_g * (255 - alpha))) / 255;
uint16_t fg_b = (fg & 0x001F) >> 0;
uint16_t bg_b = (bg & 0x001F) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
return (r << 11) | (g << 5) | 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 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;
bg_r |= bg_r >> 5;
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
uint16_t fg_g = (fg & 0x07E0) >> 3;
fg_g |= fg_g >> 6;
uint16_t bg_g = (bg & 0x07E0) >> 3;
bg_g |= bg_g >> 6;
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
uint16_t fg_b = (fg & 0x001F) << 3;
fg_b |= fg_b >> 5;
uint16_t bg_b = (bg & 0x001F) << 3;
bg_b |= bg_b >> 5;
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
// Blends foreground and background colors with 8-bit alpha
//
// Returns a color in 32-bit format
//
// If `alpha` is 0, the function returns the background color
// If `alpha` is 255, the function returns the foreground color
static inline gl_color32_t gl_color32_blend_a8(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;
bg_r |= bg_r >> 5;
uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255;
uint16_t fg_g = (fg & 0x07E0) >> 3;
fg_g |= fg_g >> 6;
uint16_t bg_g = (bg & 0x07E0) >> 3;
bg_g |= bg_g >> 6;
uint16_t g = (fg_g * alpha + (bg_g * (255 - alpha))) / 255;
uint16_t fg_b = (fg & 0x001F) << 3;
fg_b |= fg_b >> 5;
uint16_t bg_b = (bg & 0x001F) << 3;
bg_b |= bg_b >> 5;
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
#elif GL_COLOR_32BIT
// 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 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;
uint16_t fg_g = (fg & 0x0000FF00) >> 8;
uint16_t bg_g = (bg & 0x0000FF00) >> 8;
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
uint16_t fg_b = (fg & 0x000000FF) >> 0;
uint16_t bg_b = (bg & 0x000000FF) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
return gl_color16_rgb(r, g, b)
}
// Blends foreground and background colors with 8-bit alpha
//
// Returns a color in 16-bit format
//
// If `alpha` is 0, the function returns the background color
// If `alpha` is 255, the function returns the foreground color
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;
uint16_t fg_g = (fg & 0x0000FF00) >> 8;
uint16_t bg_g = (bg & 0x0000FF00) >> 8;
uint16_t g = (fg_g * alpha + (bg_g * (255 - alpha))) / 255;
uint16_t fg_b = (fg & 0x000000FF) >> 0;
uint16_t bg_b = (bg & 0x000000FF) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
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 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;
uint16_t fg_g = (fg & 0x0000FF00) >> 8;
uint16_t bg_g = (bg & 0x0000FF00) >> 8;
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
uint16_t fg_b = (fg & 0x000000FF) >> 0;
uint16_t bg_b = (bg & 0x000000FF) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
return gl_color32_rgb(r, g, b);
}
#else
#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 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 gl_color32_t* gl_color32_gradient_a4(gl_color_t fg, gl_color_t bg);
#endif // TREZORHAL_GL_COLOR_H

@ -0,0 +1,270 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <display.h>
#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_clear(void) {
gl_bitblt_t bb = {
// Destination bitmap
.height = DISPLAY_RESX,
.width = DISPLAY_RESY,
.dst_row = NULL,
.dst_x = 0,
.dst_y = 0,
.dst_stride = 0,
// Source bitmap
.src_fg = 0,
.src_alpha = 255,
};
display_fill(&bb);
}
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;
}
gl_bitblt_t bb = {
// 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(&bb);
}
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;
}
gl_bitblt_t bb = {
// 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(&bb);
}
#endif
#if TREZOR_FONT_BPP == 4
if (bitmap->format == GL_FORMAT_MONO4) {
display_copy_mono4(&bb);
}
#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_offset_t pos, 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 || pos.x >= DISPLAY_RESX) {
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(gl_rect(pos.x, pos.y, DISPLAY_RESX, DISPLAY_RESY), &bitmap);
pos.x += GLYPH_ADVANCE(glyph);
}
}
// ===============================================================
// emulation of legacy functions
void display_clear(void) { gl_clear(); }
void display_bar(int x, int y, int w, int h, uint16_t c) {
gl_draw_bar(gl_rect_wh(x, y, w, h), c);
}
void display_text(int x, int y, const char* text, int textlen, int font,
uint16_t fg_color, uint16_t bg_color) {
gl_text_attr_t attr = {
.font = font,
.fg_color = fg_color,
.bg_color = bg_color,
};
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
gl_draw_text(gl_offset(x, y), text, maxlen, &attr);
}
void display_text_center(int x, int y, const char* text, int textlen, int font,
uint16_t fg_color, uint16_t bg_color) {
gl_text_attr_t attr = {
.font = font,
.fg_color = fg_color,
.bg_color = bg_color,
};
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
int w = font_text_width(font, text, textlen);
gl_draw_text(gl_offset(x - w / 2, y), text, maxlen, &attr);
}

@ -0,0 +1,149 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GL_DRAW_H
#define GL_DRAW_H
#include "gl_color.h"
// 2D rectangle coordinates
//
// `x0`, `y0` - top-left coordinates
// `x1`, `y1` - bottom-right coordinates point (not included)
typedef struct {
int16_t x0;
int16_t y0;
int16_t x1;
int16_t y1;
} gl_rect_t;
// Builds a rectangle (`gl_rect_t`) 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;
}
// Builds a rectangle (`gl_rect_t`) 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;
// Builds a `gl_offset_t` structure
static inline gl_offset_t gl_offset(int16_t x, int16_t y) {
gl_offset_t offset = {
.x = x,
.y = y,
};
return offset;
}
// 2D size in pixels
typedef struct {
int16_t x;
int16_t y;
} gl_size_t;
// Builds a `gl_size_t` structure
static inline gl_size_t gl_size(int16_t x, int16_t y) {
gl_size_t size = {
.x = x,
.y = y,
};
return size;
}
// Format of pixels in a bitmap
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 reference
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 (font and color)
typedef struct {
// Font identifier
int font;
// Foreground color
gl_color_t fg_color;
// Background 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);
// Draws a text to the specified position.
//
// `offset` - the most left point on the font baseline
// `text` - utf-8 text
// `maxlen` - maximum number of characters displayed (use SIZE_MAX when not
// specified) `attr` - font & text color
void gl_draw_text(gl_offset_t offset, const char* text, size_t maxlen,
const gl_text_attr_t* attr);
#endif // GL_DRAW_H

@ -24,7 +24,8 @@
#include "display.h"
#include TREZOR_BOARD
#ifndef TREZOR_PRINT_DISABLE
#include "fonts/fonts.h"
#include "gl_draw.h"
#define TERMINAL_COLS (DISPLAY_RESX / 6)
#define TERMINAL_ROWS (DISPLAY_RESY / 8)
@ -39,6 +40,62 @@ void term_set_color(uint16_t fgcolor, uint16_t bgcolor) {
terminal_bgcolor = bgcolor;
}
#ifdef NEW_RENDERING
// Font_Bitmap contains 96 (0x20 - 0x7F) 5x7 glyphs
// Each glyph consists of 5 bytes (each byte represents one column)
//
// This function converts the glyph into the format compatible
// with `display_copy_mono1p()` functions.
static uint64_t term_glyph_bits(char ch) {
union {
uint64_t u64;
uint8_t bytes[8];
} result = {0};
if (ch > ' ' && ch < 128) {
const uint8_t *b = &Font_Bitmap[(ch - ' ') * 5];
for (int y = 0; y < 7; y++) {
uint8_t mask = 1 << y;
result.bytes[y] |= ((b[0] & mask) ? 128 : 0) + ((b[1] & mask) ? 64 : 0) +
((b[2] & mask) ? 32 : 0) + ((b[3] & mask) ? 16 : 0) +
((b[4] & mask) ? 8 : 0);
}
}
return result.u64;
}
// Redraws specified rows to the display
static void term_redraw_rows(int start_row, int row_count) {
uint64_t glyph_bits = 0;
gl_bitblt_t bb = {
.height = 8,
.width = 6,
.dst_row = NULL,
.dst_x = 0,
.dst_y = 0,
.dst_stride = 0,
.src_row = &glyph_bits,
.src_x = 0,
.src_y = 0,
.src_stride = 8,
.src_fg = terminal_fgcolor,
.src_bg = terminal_bgcolor,
};
for (int y = start_row; y < start_row + row_count; y++) {
bb.dst_y = y * 8;
for (int x = 0; x < TERMINAL_COLS; x++) {
glyph_bits = term_glyph_bits(terminal_fb[y][x]);
bb.dst_x = x * 6;
display_copy_mono1p(&bb);
}
}
}
#endif // NEW_RENDERING
// display text using bitmap font
void term_print(const char *text, int textlen) {
static uint8_t row = 0, col = 0;
@ -77,6 +134,10 @@ void term_print(const char *text, int textlen) {
}
}
#ifdef NEW_RENDERING
term_redraw_rows(0, TERMINAL_ROWS);
display_refresh();
#else // NEW RENDERING
// 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 +166,7 @@ void term_print(const char *text, int textlen) {
}
display_pixeldata_dirty();
display_refresh();
#endif
}
#ifdef TREZOR_EMULATOR
@ -127,5 +189,3 @@ void term_printf(const char *fmt, ...) {
va_end(va);
}
}
#endif // TREZOR_PRINT_DISABLE

@ -22,11 +22,9 @@
#include "colors.h"
#ifndef TREZOR_PRINT_DISABLE
void term_set_color(uint16_t fgcolor, uint16_t bgcolor);
void term_print(const char *text, int textlen);
void term_printf(const char *fmt, ...)
__attribute__((__format__(__printf__, 1, 2)));
#endif
#endif // LIB_TERMINAL_H

@ -26,6 +26,7 @@
#include "button.h"
#include "common.h"
#include "display.h"
#include "display_draw.h"
#include "display_utils.h"
#include "fault_handlers.h"
#include "flash.h"

@ -25,6 +25,7 @@
#include "common.h"
#include "display.h"
#include "display_draw.h"
#include "flash.h"
#include "image.h"
#include "model.h"
@ -32,6 +33,7 @@
#include "sbu.h"
#include "sdcard.h"
#include "secbool.h"
#include "terminal.h"
#include "touch.h"
#ifdef USE_HASH_PROCESSOR
@ -56,8 +58,7 @@ static void flash_from_sdcard(const flash_area_t* area, uint32_t source,
ensure(sdcard_read_blocks(buf, i + source / SDCARD_BLOCK_SIZE, 1),
"sdcard_read_blocks");
for (uint32_t j = 0; j < SDCARD_BLOCK_SIZE / FLASH_BLOCK_SIZE)
; j++) {
for (uint32_t j = 0; j < (SDCARD_BLOCK_SIZE / FLASH_BLOCK_SIZE); j++) {
ensure(flash_area_write_block(
area, i * SDCARD_BLOCK_SIZE + j * FLASH_BLOCK_SIZE,
&buf[j * FLASH_BLOCK_WORDS]),

@ -1,12 +1,15 @@
#include TREZOR_BOARD
#include "buffers.h"
#include "button.h"
#include "common.h"
#include "display.h"
#include "display_interface.h"
#include "display_draw.h"
#include "dma2d.h"
#include "dma2d_bitblt.h"
#include "flash.h"
#include "fonts/fonts.h"
#include "gl_bitblt.h"
#include "haptic.h"
#include "model.h"
#include "rgb_led.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

@ -11,7 +11,11 @@
//#define USE_DISP_I8080_8BIT_DW 1
#define USE_HASH_PROCESSOR 1
#include "displays/dsi.h"
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888
#define DISPLAY_LEGACY_HEADER "displays/dsi.h"
#define I2C_COUNT 1
#define I2C_INSTANCE_0 I2C5

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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 USE_SD_CARD 1
@ -16,8 +13,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
@ -26,10 +26,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

@ -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

@ -17,13 +17,22 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _DISPLAY_INTERFACE_H
#define _DISPLAY_INTERFACE_H
#ifndef TREZORHAL_DISPLAY_H
#define TREZORHAL_DISPLAY_H
#if NEW_RENDERING
#include <xdisplay.h>
#else
#include <stdint.h>
#include "common.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
@ -68,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 //_DISPLAY_INTERFACE_H
#endif // NEW_RENDERING
#endif // TREZORHAL_DISPLAY_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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_DMA2D_BITBLT_H
#define TREZORHAL_DMA2D_BITBLT_H
#include "gl_bitblt.h"
// Returns `true` if the specified address is accessible by DMA2D
// and can be used by any of the following functions
bool dma2d_accessible(const void* ptr);
// Waits until any pending DMA2D operation is finished
void dma2d_wait(void);
// Following functions are hardware (DMA2D) accelerated versions
// of `gl_rgb565_xxx()` and `gl_rgba8888_xxx()` function from `gl_bitblt.h`
void dma2d_rgb565_fill(const gl_bitblt_t* bb);
void dma2d_rgb565_copy_mono4(const gl_bitblt_t* bb);
void dma2d_rgb565_copy_rgb565(const gl_bitblt_t* bb);
void dma2d_rgb565_blend_mono4(const gl_bitblt_t* bb);
void dma2d_rgba8888_fill(const gl_bitblt_t* bb);
void dma2d_rgba8888_copy_mono4(const gl_bitblt_t* bb);
void dma2d_rgba8888_copy_rgb565(const gl_bitblt_t* bb);
void dma2d_rgba8888_copy_rgba8888(const gl_bitblt_t* bb);
void dma2d_rgba8888_blend_mono4(const gl_bitblt_t* bb);
#endif // TREZORHAL_DMA2D_BITBLT_H

@ -220,7 +220,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();

@ -0,0 +1,222 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <xdisplay.h>
#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) {
#ifdef XFRAMEBUFFER
#ifndef BOARDLOADER
bg_copy_wait();
#endif
#endif
}
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
}
void display_set_compatible_settings(void) { display_panel_set_big_endian(); }
static inline void set_window(const gl_bitblt_t* bb) {
display_panel_set_window(bb->dst_x, bb->dst_y, bb->dst_x + bb->width - 1,
bb->dst_y + bb->height + 1);
}
void display_fill(const gl_bitblt_t* bb) {
set_window(bb);
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
ISSUE_PIXEL_DATA(bb->src_fg);
}
}
}
void display_copy_rgb565(const gl_bitblt_t* bb) {
set_window(bb);
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
ISSUE_PIXEL_DATA(src_ptr[x]);
}
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
void display_copy_mono1p(const gl_bitblt_t* bb) {
set_window(bb);
uint8_t* src = (uint8_t*)bb->src_row;
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
uint8_t data = src[(src_ofs + x) / 8];
ISSUE_PIXEL_DATA((data & mask) ? bb->src_fg : bb->src_bg);
}
src_ofs += bb->src_stride;
}
}
void display_copy_mono4(const gl_bitblt_t* bb) {
set_window(bb);
const gl_color16_t* gradient = gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
uint8_t* src_row = (uint8_t*)bb->src_row;
uint16_t height = bb->height;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
ISSUE_PIXEL_DATA(gradient[fg_lum]);
}
src_row += bb->src_stride / sizeof(*src_row);
}
}

@ -0,0 +1,172 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "display_fb.h"
#include "display_io.h"
#include "display_panel.h"
#include "xdisplay.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;
#ifndef BOARDLOADER
static bool pending_fb_switch = false;
#endif
#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
display_fb_info_t display_get_frame_buffer(void) {
void *addr;
if (current_frame_buffer == 0) {
addr = (void *)physical_frame_buffer_1;
} else {
addr = (void *)physical_frame_buffer_0;
}
display_fb_info_t fb = {
.ptr = addr,
.stride = DISPLAY_RESX * sizeof(uint16_t),
};
return fb;
}
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

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
#define TREZOR_HAL_DISPLAY_INTERNAL_H
#include TREZOR_BOARD
#include <stdint.h>
#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

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

@ -0,0 +1,244 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// 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;
// Window padding (correction) when using 90dg or 270dg orientation
// (internally the display is 240x320 but we use only 240x240)
static display_padding_t g_window_padding;
#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_panel_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) {
x0 += g_window_padding.x;
x1 += g_window_padding.x;
y0 += g_window_padding.y;
y1 += g_window_padding.y;
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_panel_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, &g_window_padding);
} else {
lx154a2422_rotate(angle, &g_window_padding);
}
#else
lx154a2422_rotate(angle, &g_window_padding);
#endif
}

@ -0,0 +1,57 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_ST7789_PANEL_H
#define TREZORHAL_ST7789_PANEL_H
#include <stdbool.h>
#include <stdint.h>
// 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
typedef struct {
uint16_t x;
uint16_t y;
} display_padding_t;
// 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

@ -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 <http://www.gnu.org/licenses/>.
*/
#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);
}

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef _154A_H_
#define _154A_H_
// ILI9341 IC controller
void _154a_init_seq(void);
#endif

@ -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();
}

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef LX154A2411_H_
#define LX154A2411_H_
// ST7789_V IC controller
void lx154a2411_gamma(void);
void lx154a2411_init_seq(void);
#endif

@ -0,0 +1,159 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "lx154a2422.h"
#include "../display_io.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, display_padding_t* padding) {
uint16_t shift = 0;
char BX = 0, BY = 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;
BY = 0;
break;
case 90:
display_command_parameter = MV | MX | MH | ML;
BX = 1;
shift = 1;
break;
case 180:
display_command_parameter = MX | MY | MH | ML;
BY = 0;
shift = 1;
break;
case 270:
display_command_parameter = MV | MY;
BX = 1;
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);
}
padding->x = BX ? (320 - DISPLAY_RESY) : 0;
padding->y = BY ? (320 - DISPLAY_RESY) : 0;
}

@ -0,0 +1,29 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef LX154A2422_H_
#define LX154A2422_H_
#include "../display_panel.h"
void lx154a2422_init_seq(void);
void lx154a2422_gamma(void);
void lx154a2422_rotate(int degrees, display_padding_t* padding);
#endif

@ -0,0 +1,174 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "tf15411a.h"
#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, display_padding_t* padding) {
uint16_t shift = 0;
char BX = 0, BY = 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;
BY = 1;
break;
case 90:
display_command_parameter = MV | MX | MH | ML;
BX = 0;
shift = 1;
break;
case 180:
display_command_parameter = MX | MY | MH | ML;
BY = 1;
shift = 1;
break;
case 270:
display_command_parameter = MV | MY;
BX = 0;
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);
}
padding->x = BX ? (320 - DISPLAY_RESY) : 0;
padding->y = BY ? (320 - DISPLAY_RESY) : 0;
}

@ -0,0 +1,30 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TF15411A_H_
#define TF15411A_H_
#include "../display_panel.h"
// GC9307 IC controller
void tf15411a_init_seq(void);
void tf15411a_rotate(int degrees, display_padding_t* padding);
#endif

@ -0,0 +1,144 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#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 {
// Pointer to the frame buffer
uint16_t *framebuf;
// 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));
drv->framebuf = (uint16_t *)FRAME_BUFFER_ADDR;
// 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));
drv->framebuf = (uint16_t *)FRAME_BUFFER_ADDR;
}
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;
}
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
display_fb_info_t fb = {
.ptr = (void *)drv->framebuf,
.stride = DISPLAY_RESX * sizeof(uint16_t),
};
return fb;
}
void display_refresh(void) {
// Do nothing as using just a single frame buffer
}
void display_set_compatible_settings() {}
void display_fill(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y);
bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
gl_rgb565_fill(&bb_new);
}
void display_copy_rgb565(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y);
bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
gl_rgb565_copy_rgb565(&bb_new);
}
void display_copy_mono4(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y);
bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
gl_rgb565_copy_mono4(&bb_new);
}

@ -0,0 +1,36 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_DISPLAY_INTERNAL_H
#define TREZORHAL_DISPLAY_INTERNAL_H
#include TREZOR_BOARD
#include STM32_HAL_H
#include "sdram.h"
// 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)
// Initializes LTDC controller and I/O pins
void BSP_LCD_Init(void);
#endif // TREZORHAL_DISPLAY_INTERNAL_H

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#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);
}

@ -0,0 +1,512 @@
#include <stdint.h>
#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; /*<! Value of Timeout when SPI communication fails */
/* SPIx bus function */
static void SPIx_Init(void);
static void ili9341_Write(uint16_t Value);
static uint32_t ili9341_Read(uint8_t ReadSize);
static void ili9341_Error(void);
/**
* @brief SPIx Bus initialization
*/
static void SPIx_Init(void) {
if (HAL_SPI_GetState(&SpiHandle) == HAL_SPI_STATE_RESET) {
/* SPI configuration -----------------------------------------------------*/
SpiHandle.Instance = DISCOVERY_SPIx;
/* SPI baudrate is set to 5.6 MHz (PCLK2/SPI_BaudRatePrescaler = 90/16
= 5.625 MHz) to verify these constraints:
- ILI9341 LCD SPI interface max baudrate is 10MHz for write and 6.66MHz
for read
- l3gd20 SPI interface max baudrate is 10MHz for write/read
- PCLK2 frequency is set to 90 MHz
*/
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
/* On STM32F429I-Discovery, LCD ID cannot be read then keep a common
* configuration */
/* for LCD and GYRO (SPI_DIRECTION_2LINES) */
/* Note: To read a register a LCD, SPI_DIRECTION_1LINE should be set */
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLED;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
HAL_SPI_Init(&SpiHandle);
}
}
/**
* @brief SPIx error treatment function.
*/
static void ili9341_Error(void) {
/* De-initialize the SPI communication BUS */
HAL_SPI_DeInit(&SpiHandle);
/* Re- Initialize the SPI communication BUS */
SPIx_Init();
}
/**
* @brief Reads 4 bytes from device.
* @param ReadSize: Number of bytes to read (max 4 bytes)
* @retval Value read on the SPI
*/
static uint32_t ili9341_Read(uint8_t ReadSize) {
HAL_StatusTypeDef status = HAL_OK;
uint32_t readvalue;
status =
HAL_SPI_Receive(&SpiHandle, (uint8_t*)&readvalue, ReadSize, SpixTimeout);
/* Check the communication status */
if (status != HAL_OK) {
/* Re-Initialize the BUS */
ili9341_Error();
}
return readvalue;
}
/**
* @brief Writes a byte to device.
* @param Value: value to be written
*/
static void ili9341_Write(uint16_t Value) {
HAL_StatusTypeDef status = HAL_OK;
status = HAL_SPI_Transmit(&SpiHandle, (uint8_t*)&Value, 1, SpixTimeout);
/* Check the communication status */
if (status != HAL_OK) {
/* Re-Initialize the BUS */
ili9341_Error();
}
}
void ili9341_spi_init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure NCS in Output Push-Pull mode */
LCD_WRX_GPIO_CLK_ENABLE();
GPIO_InitStructure.Pin = LCD_WRX_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(LCD_WRX_GPIO_PORT, &GPIO_InitStructure);
LCD_RDX_GPIO_CLK_ENABLE();
GPIO_InitStructure.Pin = LCD_RDX_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(LCD_RDX_GPIO_PORT, &GPIO_InitStructure);
/* Configure the LCD Control pins ----------------------------------------*/
LCD_NCS_GPIO_CLK_ENABLE();
/* Configure NCS in Output Push-Pull mode */
GPIO_InitStructure.Pin = LCD_NCS_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(LCD_NCS_GPIO_PORT, &GPIO_InitStructure);
/* Set or Reset the control line */
LCD_CS_LOW();
LCD_CS_HIGH();
/* Enable SPIx clock */
DISCOVERY_SPIx_CLK_ENABLE();
/* Enable DISCOVERY_SPI GPIO clock */
DISCOVERY_SPIx_GPIO_CLK_ENABLE();
/* configure SPI SCK, MOSI and MISO */
GPIO_InitStructure.Pin = (DISCOVERY_SPIx_SCK_PIN | DISCOVERY_SPIx_MOSI_PIN |
DISCOVERY_SPIx_MISO_PIN);
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
GPIO_InitStructure.Speed = GPIO_SPEED_MEDIUM;
GPIO_InitStructure.Alternate = DISCOVERY_SPIx_AF;
HAL_GPIO_Init(DISCOVERY_SPIx_GPIO_PORT, &GPIO_InitStructure);
SPIx_Init();
}
/**
* @brief Writes register value.
*/
void ili9341_WriteData(uint16_t RegValue) {
/* Set WRX to send data */
LCD_WRX_HIGH();
/* Reset LCD control line(/CS) and Send data */
LCD_CS_LOW();
ili9341_Write(RegValue);
/* Deselect: Chip Select high */
LCD_CS_HIGH();
}
/**
* @brief Writes register address.
*/
void ili9341_WriteReg(uint8_t Reg) {
/* Reset WRX to send command */
LCD_WRX_LOW();
/* Reset LCD control line(/CS) and Send command */
LCD_CS_LOW();
ili9341_Write(Reg);
/* Deselect: Chip Select high */
LCD_CS_HIGH();
}
/**
* @brief Reads register value.
* @param RegValue Address of the register to read
* @param ReadSize Number of bytes to read
* @retval Content of the register value
*/
uint32_t ili9341_ReadData(uint16_t RegValue, uint8_t ReadSize) {
uint32_t readvalue = 0;
/* Select: Chip Select low */
LCD_CS_LOW();
/* Reset WRX to send command */
LCD_WRX_LOW();
ili9341_Write(RegValue);
readvalue = ili9341_Read(ReadSize);
/* Set WRX to send data */
LCD_WRX_HIGH();
/* Deselect: Chip Select high */
LCD_CS_HIGH();
return readvalue;
}
void ili9341_init(void) {
/* Initialize ILI9341 low level bus layer ----------------------------------*/
ili9341_spi_init();
ili9341_WriteReg(LCD_DISPLAY_OFF);
/* Configure LCD */
ili9341_WriteReg(0xCA);
ili9341_WriteData(0xC3);
ili9341_WriteData(0x08);
ili9341_WriteData(0x50);
ili9341_WriteReg(LCD_POWERB);
ili9341_WriteData(0x00);
ili9341_WriteData(0xC1);
ili9341_WriteData(0x30);
ili9341_WriteReg(LCD_POWER_SEQ);
ili9341_WriteData(0x64);
ili9341_WriteData(0x03);
ili9341_WriteData(0x12);
ili9341_WriteData(0x81);
ili9341_WriteReg(LCD_DTCA);
ili9341_WriteData(0x85);
ili9341_WriteData(0x00);
ili9341_WriteData(0x78);
ili9341_WriteReg(LCD_POWERA);
ili9341_WriteData(0x39);
ili9341_WriteData(0x2C);
ili9341_WriteData(0x00);
ili9341_WriteData(0x34);
ili9341_WriteData(0x02);
ili9341_WriteReg(LCD_PRC);
ili9341_WriteData(0x20);
ili9341_WriteReg(LCD_DTCB);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteReg(LCD_FRMCTR1);
ili9341_WriteData(0x00);
ili9341_WriteData(0x1B);
ili9341_WriteReg(LCD_DFC);
ili9341_WriteData(0x0A);
ili9341_WriteData(0xA2);
ili9341_WriteReg(LCD_POWER1);
ili9341_WriteData(0x10);
ili9341_WriteReg(LCD_POWER2);
ili9341_WriteData(0x10);
ili9341_WriteReg(LCD_VCOM1);
ili9341_WriteData(0x45);
ili9341_WriteData(0x15);
ili9341_WriteReg(LCD_VCOM2);
ili9341_WriteData(0x90);
ili9341_WriteReg(LCD_MAC);
ili9341_WriteData(0xC8);
ili9341_WriteReg(LCD_3GAMMA_EN);
ili9341_WriteData(0x00);
ili9341_WriteReg(LCD_RGB_INTERFACE);
ili9341_WriteData(0xC2);
ili9341_WriteReg(LCD_DFC);
ili9341_WriteData(0x0A);
ili9341_WriteData(0xA7);
ili9341_WriteData(0x27);
ili9341_WriteData(0x04);
/* Colomn address set */
ili9341_WriteReg(LCD_COLUMN_ADDR);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteData(0xEF);
/* Page address set */
ili9341_WriteReg(LCD_PAGE_ADDR);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteData(0x01);
ili9341_WriteData(0x3F);
ili9341_WriteReg(LCD_INTERFACE);
ili9341_WriteData(0x01);
ili9341_WriteData(0x00);
ili9341_WriteData(0x06);
ili9341_WriteReg(LCD_GRAM);
HAL_Delay(200);
ili9341_WriteReg(LCD_GAMMA);
ili9341_WriteData(0x01);
ili9341_WriteReg(LCD_PGAMMA);
ili9341_WriteData(0x0F);
ili9341_WriteData(0x29);
ili9341_WriteData(0x24);
ili9341_WriteData(0x0C);
ili9341_WriteData(0x0E);
ili9341_WriteData(0x09);
ili9341_WriteData(0x4E);
ili9341_WriteData(0x78);
ili9341_WriteData(0x3C);
ili9341_WriteData(0x09);
ili9341_WriteData(0x13);
ili9341_WriteData(0x05);
ili9341_WriteData(0x17);
ili9341_WriteData(0x11);
ili9341_WriteData(0x00);
ili9341_WriteReg(LCD_NGAMMA);
ili9341_WriteData(0x00);
ili9341_WriteData(0x16);
ili9341_WriteData(0x1B);
ili9341_WriteData(0x04);
ili9341_WriteData(0x11);
ili9341_WriteData(0x07);
ili9341_WriteData(0x31);
ili9341_WriteData(0x33);
ili9341_WriteData(0x42);
ili9341_WriteData(0x05);
ili9341_WriteData(0x0C);
ili9341_WriteData(0x0A);
ili9341_WriteData(0x28);
ili9341_WriteData(0x2F);
ili9341_WriteData(0x0F);
ili9341_WriteReg(LCD_SLEEP_OUT);
HAL_Delay(200);
ili9341_WriteReg(LCD_DISPLAY_ON);
/* GRAM start writing */
ili9341_WriteReg(LCD_GRAM);
}

@ -0,0 +1,13 @@
#ifndef _ILI9341_SPI_H
#define _ILI9341_SPI_H
#define ILI9341_HSYNC ((uint32_t)9) /* Horizontal synchronization */
#define ILI9341_HBP ((uint32_t)29) /* Horizontal back porch */
#define ILI9341_HFP ((uint32_t)2) /* Horizontal front porch */
#define ILI9341_VSYNC ((uint32_t)1) /* Vertical synchronization */
#define ILI9341_VBP ((uint32_t)3) /* Vertical back porch */
#define ILI9341_VFP ((uint32_t)2) /* Vertical front porch */
void ili9341_init(void);
#endif //_ILI9341_SPI_H

@ -0,0 +1,398 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#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 ? 128 : 0) | \
(*(src + (1 * DISPLAY_RESX)) >= 128 ? 64 : 0) | \
(*(src + (2 * DISPLAY_RESX)) >= 128 ? 32 : 0) | \
(*(src + (3 * DISPLAY_RESX)) >= 128 ? 16 : 0) | \
(*(src + (4 * DISPLAY_RESX)) >= 128 ? 8 : 0) | \
(*(src + (5 * DISPLAY_RESX)) >= 128 ? 4 : 0) | \
(*(src + (6 * DISPLAY_RESX)) >= 128 ? 2 : 0) | \
(*(src + (7 * DISPLAY_RESX)) >= 128 ? 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;
}
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
display_fb_info_t fb = {
.ptr = &drv->framebuf[0],
.stride = DISPLAY_RESX,
};
return fb;
}
void display_refresh(void) { display_sync_with_fb(); }
void display_set_compatible_settings() {}
void display_fill(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y];
bb_new.dst_stride = DISPLAY_RESX;
mono8_fill(&bb_new);
}
void display_copy_mono1p(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y];
bb_new.dst_stride = DISPLAY_RESX;
mono8_copy_mono1p(&bb_new);
}

@ -0,0 +1,379 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#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;
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 ? 128 : 0) | \
(*(src + (1 * DISPLAY_RESX)) >= 128 ? 64 : 0) | \
(*(src + (2 * DISPLAY_RESX)) >= 128 ? 32 : 0) | \
(*(src + (3 * DISPLAY_RESX)) >= 128 ? 16 : 0) | \
(*(src + (4 * DISPLAY_RESX)) >= 128 ? 8 : 0) | \
(*(src + (5 * DISPLAY_RESX)) >= 128 ? 4 : 0) | \
(*(src + (6 * DISPLAY_RESX)) >= 128 ? 2 : 0) | \
(*(src + (7 * DISPLAY_RESX)) >= 128 ? 1 : 0))
#define COLLECT_ROW_BYTE_REV(src) \
(0 | (*(src + (0 * DISPLAY_RESX)) >= 128 ? 1 : 0) | \
(*(src + (1 * DISPLAY_RESX)) >= 128 ? 2 : 0) | \
(*(src + (2 * DISPLAY_RESX)) >= 128 ? 4 : 0) | \
(*(src + (3 * DISPLAY_RESX)) >= 128 ? 8 : 0) | \
(*(src + (4 * DISPLAY_RESX)) >= 128 ? 16 : 0) | \
(*(src + (5 * DISPLAY_RESX)) >= 128 ? 32 : 0) | \
(*(src + (6 * DISPLAY_RESX)) >= 128 ? 64 : 0) | \
(*(src + (7 * DISPLAY_RESX)) >= 128 ? 128 : 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
if (drv->orientation_angle == 0) {
for (int y = DISPLAY_RESY / 8 - 1; y >= 0; y--) {
uint8_t buff[DISPLAY_RESX];
uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8];
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;
}
}
} else {
for (int y = 0; y < DISPLAY_RESY / 8; y++) {
uint8_t buff[DISPLAY_RESX];
uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8];
for (int x = 0; x < DISPLAY_RESX; x++) {
buff[x] = COLLECT_ROW_BYTE_REV(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;
}
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
display_fb_info_t fb = {
.ptr = &drv->framebuf[0],
.stride = DISPLAY_RESX,
};
return fb;
}
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);
}
void display_set_compatible_settings() {}
void display_fill(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y];
bb_new.dst_stride = DISPLAY_RESX;
gl_mono8_fill(&bb_new);
}
void display_copy_mono1p(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y];
bb_new.dst_stride = DISPLAY_RESX;
gl_mono8_copy_mono1p(&bb_new);
}

@ -19,7 +19,7 @@
#include <stdint.h>
#include TREZOR_BOARD
#include "display_interface.h"
#include "display.h"
#include "memzero.h"
#include STM32_HAL_H
@ -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) {}

@ -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

@ -1,5 +1,5 @@
#include "display_interface.h"
#include "display.h"
#include "displays/st7789v.h"
#include "touch.h"

@ -1,4 +1,4 @@
#include "display_interface.h"
#include "display.h"
#include "displays/st7789v.h"
void tf15411a_init_seq(void) {

@ -22,7 +22,7 @@
#include <string.h>
#include TREZOR_BOARD
#include "backlight_pwm.h"
#include "display_interface.h"
#include "display.h"
#include "irq.h"
#include "memzero.h"
#include "st7789v.h"
@ -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();

@ -19,7 +19,7 @@
#include <stdint.h>
#include TREZOR_BOARD
#include "display_interface.h"
#include "display.h"
#include "memzero.h"
#include STM32_HAL_H

@ -20,7 +20,7 @@
#include <stdbool.h>
#include <stdint.h>
#include TREZOR_BOARD
#include "display_interface.h"
#include "display.h"
#include STM32_HAL_H
#ifdef USE_CONSUMPTION_MASK

@ -20,7 +20,7 @@
#include "dma2d.h"
#include "colors.h"
#include STM32_HAL_H
#include "display_interface.h"
#include "display.h"
typedef enum {
DMA2D_LAYER_FG = 1,

@ -0,0 +1,616 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include STM32_HAL_H
#include <stddef.h>
#include "dma2d_bitblt.h"
#include "gl_color.h"
static DMA2D_HandleTypeDef dma2d_handle = {
.Instance = (DMA2D_TypeDef*)DMA2D_BASE,
};
bool dma2d_accessible(const void* ptr) {
#ifdef STM32F4
const void* ccm_start = (const void*)0x10000000;
const void* ccm_end = (const void*)0x1000FFFF;
return !(ptr >= ccm_start && ptr <= ccm_end);
#else
return true;
#endif
}
void dma2d_wait(void) {
while (HAL_DMA2D_PollForTransfer(&dma2d_handle, 10) != HAL_OK)
;
}
void dma2d_rgb565_fill(const gl_bitblt_t* bb) {
dma2d_wait();
if (bb->src_alpha == 255) {
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
dma2d_handle.Init.Mode = DMA2D_R2M;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
HAL_DMA2D_Start(&dma2d_handle, gl_color_to_color32(bb->src_fg),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
bb->width, bb->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, bb->dst_stride / sizeof(uint16_t) - bb->width);
MODIFY_REG(dma2d_handle.Instance->NLR, (DMA2D_NLR_NL|DMA2D_NLR_PL),
(bb->height| (bb->width << 16))); WRITE_REG(dma2d_handle.Instance->OMAR,
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t));
WRITE_REG(dma2d_handle.Instance->OCOLR,
gl_color_to_color32(bb->src_fg));
((dma2d_handle).Instance->CR |= DMA2D_CR_START);
*/
} else {
#ifdef STM32U5
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND_FG;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[1].InputOffset = 0;
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[0].InputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
dma2d_handle.LayerCfg[0].AlphaMode = 0;
dma2d_handle.LayerCfg[0].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
HAL_DMA2D_BlendingStart(
&dma2d_handle, gl_color_to_color32(bb->src_fg),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t), bb->width,
bb->height);
#else
// STM32F4 can not accelerate blending with the fixed color
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint16_t height = bb->height;
uint8_t alpha = bb->src_alpha;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = gl_color16_blend_a8(
bb->src_fg, gl_color16_to_color(dst_ptr[x]), alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
}
#endif
}
}
/*
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 {
gl_color32_t gradient[GRADIENT_STEPS];
} cache[LAYER_COUNT] = { 0 };
if (layer >= LAYER_COUNT) {
return;
}
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] = gl_color32_blend_a4(fg, bg, step);
}
DMA2D_CLUTCfgTypeDef clut;
clut.CLUTColorMode = DMA2D_CCM_ARGB8888;
clut.Size = GRADIENT_STEPS - 1;
clut.pCLUT = gradient;
HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut, layer);
while (HAL_DMA2D_PollForTransfer(&dma2d_handle, 10) != HAL_OK)
;
}
}*/
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 {
gl_color_t c_fg;
gl_color_t c_bg;
} cache[LAYER_COUNT] = {0};
if (layer >= LAYER_COUNT) {
return;
}
volatile uint32_t* clut =
layer ? dma2d_handle.Instance->FGCLUT : dma2d_handle.Instance->BGCLUT;
if (fg != cache[layer].c_fg || bg != cache[layer].c_bg) {
cache[layer].c_fg = fg;
cache[layer].c_bg = bg;
for (int step = 0; step < GRADIENT_STEPS; step++) {
clut[step] = gl_color32_blend_a4(fg, bg, step);
}
DMA2D_CLUTCfgTypeDef clut;
clut.CLUTColorMode = DMA2D_CCM_ARGB8888;
clut.Size = GRADIENT_STEPS - 1;
clut.pCLUT = 0; // ???
HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut, layer);
}
}
static void dma2d_rgb565_copy_mono4_first_col(gl_bitblt_t* bb,
const gl_color16_t* gradient) {
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_lum = src_ptr[0] >> 4;
dst_ptr[0] = gradient[fg_lum];
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
static void dma2d_rgb565_copy_mono4_last_col(gl_bitblt_t* bb,
const gl_color16_t* gradient) {
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_lum = src_ptr[0] & 0x0F;
dst_ptr[0] = gradient[fg_lum];
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
void dma2d_rgb565_copy_mono4(const gl_bitblt_t* params) {
const gl_color16_t* src_gradient = NULL;
gl_bitblt_t bb_copy = *params;
gl_bitblt_t* bb = &bb_copy;
dma2d_wait();
if (bb->src_x & 1) {
// First column of mono4 bitmap is odd
// Use the CPU to draw the first column
src_gradient = gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
dma2d_rgb565_copy_mono4_first_col(bb, src_gradient);
bb->dst_x += 1;
bb->src_x += 1;
bb->width -= 1;
}
if (bb->width > 0 && bb->width & 1) {
// The width is odd
// Use the CPU to draw the last column
if (src_gradient == NULL) {
src_gradient = gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
}
dma2d_rgb565_copy_mono4_last_col(bb, src_gradient);
bb->width -= 1;
}
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4;
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_config_clut(1, bb->src_fg, bb->src_bg);
HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
bb->width, bb->height);
}
void dma2d_rgb565_copy_rgb565(const gl_bitblt_t* bb) {
dma2d_wait();
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[1].InputOffset =
bb->src_stride / sizeof(uint16_t) - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
HAL_DMA2D_Start(&dma2d_handle,
(uint32_t)bb->src_row + bb->src_x * sizeof(uint16_t),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
bb->width, bb->height);
}
static void dma2d_rgb565_blend_mono4_first_col(const gl_bitblt_t* bb) {
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] >> 4;
dst_ptr[0] = gl_color16_blend_a4(bb->src_fg,
gl_color16_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
static void dma2d_rgb565_blend_mono4_last_col(const gl_bitblt_t* bb) {
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] & 0x0F;
dst_ptr[0] = gl_color16_blend_a4(bb->src_fg,
gl_color16_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
void dma2d_rgb565_blend_mono4(const gl_bitblt_t* params) {
dma2d_wait();
gl_bitblt_t bb_copy = *params;
gl_bitblt_t* bb = &bb_copy;
if (bb->src_x & 1) {
// First column of mono4 bitmap is odd
// Use the CPU to draw the first column
dma2d_rgb565_blend_mono4_first_col(bb);
bb->dst_x += 1;
bb->src_x += 1;
bb->width -= 1;
}
if (bb->width > 0 && bb->width & 1) {
// The width is odd
// Use the CPU to draw the last column
dma2d_rgb565_blend_mono4_last_col(bb);
bb->width -= 1;
}
if (bb->width > 0) {
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = gl_color_to_color32(bb->src_fg);
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[0].InputOffset =
bb->dst_stride / sizeof(uint16_t) - bb->width;
dma2d_handle.LayerCfg[0].AlphaMode = 0;
dma2d_handle.LayerCfg[0].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
HAL_DMA2D_BlendingStart(
&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t), bb->width,
bb->height);
}
}
void dma2d_rgba8888_fill(const gl_bitblt_t* bb) {
dma2d_wait();
if (bb->src_alpha == 255) {
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_R2M;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
HAL_DMA2D_Start(&dma2d_handle, gl_color_to_color32(bb->src_fg),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
bb->width, bb->height);
} else {
#ifdef STM32U5
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND_FG;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[1].InputOffset = 0;
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[0].InputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
dma2d_handle.LayerCfg[0].AlphaMode = 0;
dma2d_handle.LayerCfg[0].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
HAL_DMA2D_BlendingStart(
&dma2d_handle, gl_color_to_color32(bb->src_fg),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t), bb->width,
bb->height);
#else
// STM32F4 can not accelerate blending with the fixed color
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint16_t height = bb->height;
uint8_t alpha = bb->src_alpha;
while (height-- > 0) {
for (int x = 0; x < bb->width; x++) {
dst_ptr[x] = gl_color32_blend_a8(
bb->src_fg, gl_color32_to_color(dst_ptr[x]), alpha);
}
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
}
#endif
}
}
static void dma2d_rgba8888_copy_mono4_first_col(gl_bitblt_t* bb,
const gl_color32_t* gradient) {
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_lum = src_ptr[0] >> 4;
dst_ptr[0] = gradient[fg_lum];
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
static void dma2d_rgba8888_copy_mono4_last_col(gl_bitblt_t* bb,
const gl_color32_t* gradient) {
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_lum = src_ptr[0] & 0x0F;
dst_ptr[0] = gradient[fg_lum];
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
void dma2d_rgba8888_copy_mono4(const gl_bitblt_t* params) {
const gl_color32_t* src_gradient = NULL;
gl_bitblt_t bb_copy = *params;
gl_bitblt_t* bb = &bb_copy;
dma2d_wait();
if (bb->src_x & 1) {
// First column of mono4 bitmap is odd
// Use the CPU to draw the first column
src_gradient = gl_color32_gradient_a4(bb->src_fg, bb->src_bg);
dma2d_rgba8888_copy_mono4_first_col(bb, src_gradient);
bb->dst_x += 1;
bb->src_x += 1;
bb->width -= 1;
}
if (bb->width > 0 && bb->width & 1) {
// The width is odd
// Use the CPU to draw the last column
if (src_gradient == NULL) {
src_gradient = gl_color32_gradient_a4(bb->src_fg, bb->src_bg);
}
dma2d_rgba8888_copy_mono4_last_col(bb, src_gradient);
bb->width -= 1;
}
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4;
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_config_clut(1, bb->src_fg, bb->src_bg);
HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
bb->width, bb->height);
}
void dma2d_rgba8888_copy_rgb565(const gl_bitblt_t* bb) {
dma2d_wait();
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
dma2d_handle.LayerCfg[1].InputOffset =
bb->src_stride / sizeof(uint16_t) - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
HAL_DMA2D_Start(&dma2d_handle,
(uint32_t)bb->src_row + bb->src_x * sizeof(uint16_t),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
bb->width, bb->height);
}
static void dma2d_rgba8888_blend_mono4_first_col(const gl_bitblt_t* bb) {
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] >> 4;
dst_ptr[0] = gl_color32_blend_a4(bb->src_fg,
gl_color32_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
static void dma2d_rgba8888_blend_mono4_last_col(const gl_bitblt_t* bb) {
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
int height = bb->height;
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] & 0x0F;
dst_ptr[0] = gl_color32_blend_a4(bb->src_fg,
gl_color32_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
src_ptr += bb->src_stride / sizeof(*src_ptr);
}
}
void dma2d_rgba8888_blend_mono4(const gl_bitblt_t* params) {
dma2d_wait();
gl_bitblt_t bb_copy = *params;
gl_bitblt_t* bb = &bb_copy;
if (bb->src_x & 1) {
// First column of mono4 bitmap is odd
// Use the CPU to draw the first column
dma2d_rgba8888_blend_mono4_first_col(bb);
bb->dst_x += 1;
bb->src_x += 1;
bb->width -= 1;
}
if (bb->width > 0 && bb->width & 1) {
// The width is odd
// Use the CPU to draw the last column
dma2d_rgba8888_blend_mono4_last_col(bb);
bb->width -= 1;
}
if (bb->width > 0) {
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = gl_color_to_color32(bb->src_fg);
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[0].InputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
dma2d_handle.LayerCfg[0].AlphaMode = 0;
dma2d_handle.LayerCfg[0].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
HAL_DMA2D_BlendingStart(
&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t), bb->width,
bb->height);
}
}
void dma2d_rgba8888_copy_rgba8888(const gl_bitblt_t* bb) {
dma2d_wait();
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
dma2d_handle.Init.OutputOffset =
bb->dst_stride / sizeof(uint32_t) - bb->width;
HAL_DMA2D_Init(&dma2d_handle);
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
dma2d_handle.LayerCfg[1].InputOffset =
bb->src_stride / sizeof(uint32_t) - bb->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
dma2d_handle.LayerCfg[1].InputAlpha = 0;
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
HAL_DMA2D_Start(&dma2d_handle,
(uint32_t)bb->src_row + bb->src_x * sizeof(uint32_t),
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
bb->width, bb->height);
}

@ -1,7 +1,7 @@
#include "secret.h"
#include <string.h>
#include "common.h"
#include "display.h"
#include "display_draw.h"
#include "flash.h"
#include "model.h"

@ -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;

@ -0,0 +1 @@
../../stm32f4/display/st-7789

@ -0,0 +1,155 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "display_internal.h"
#include "xdisplay.h"
#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;
// 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_BUFFER1_BASE_S);
} else {
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_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;
}
void display_set_compatible_settings() {}
void display_fill(const gl_bitblt_t *bb) {
display_fb_info_t fb = display_get_frame_buffer();
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gl_rgba8888_fill(&bb_new);
}
void display_copy_rgb565(const gl_bitblt_t *bb) {
display_fb_info_t fb = display_get_frame_buffer();
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gl_rgba8888_copy_rgb565(&bb_new);
}
void display_copy_mono1p(const gl_bitblt_t *bb) {
display_fb_info_t fb = display_get_frame_buffer();
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gl_rgba8888_copy_mono1p(&bb_new);
}
void display_copy_mono4(const gl_bitblt_t *bb) {
display_fb_info_t fb = display_get_frame_buffer();
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gl_rgba8888_copy_mono4(&bb_new);
}

@ -0,0 +1,77 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include <xdisplay.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;
display_fb_info_t display_get_frame_buffer(void) {
uintptr_t addr;
if (current_frame_buffer == 0) {
addr = GFXMMU_VIRTUAL_BUFFER1_BASE_S;
} else {
addr = GFXMMU_VIRTUAL_BUFFER0_BASE_S;
}
uint32_t fb_stride = FRAME_BUFFER_PIXELS_PER_LINE * sizeof(uint32_t);
// We do not utilize whole area of the display
// (discovery kit display is 480x480 and we need just 240x240)
addr += (480 - DISPLAY_RESY) / 2 * sizeof(uint32_t);
addr += (480 - DISPLAY_RESX) / 2 * fb_stride;
display_fb_info_t fb = {
.ptr = (void *)addr,
.stride = fb_stride,
};
return fb;
}
void display_refresh(void) {
if (current_frame_buffer == 0) {
current_frame_buffer = 1;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
sizeof(physical_frame_buffer_0));
} else {
current_frame_buffer = 0;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
sizeof(physical_frame_buffer_1));
}
}

@ -0,0 +1,58 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
#define TREZOR_HAL_DISPLAY_INTERNAL_H
#include <stdint.h>
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual frame buffer
// due to used GFXMMU settings
#define PHYSICAL_FRAME_BUFFER_SIZE 184320
// Pitch (in pixels) of the virtual frame buffer
#define FRAME_BUFFER_PIXELS_PER_LINE 768
// 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

@ -0,0 +1 @@
../../stm32f4/display/vg-2864

@ -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

@ -0,0 +1 @@
../stm32f4/dma2d_bitblt.c

@ -31,7 +31,7 @@
#include "common.h"
#include "display-unix.h"
#include "display_interface.h"
#include "display.h"
#include "profile.h"
#define EMULATOR_BORDER 16
@ -354,3 +354,5 @@ void display_clear_save(void) {
uint8_t *display_get_wr_addr(void) { return (uint8_t *)DISPLAY_DATA_ADDRESS; }
void display_finish_actions(void) {}
void display_reinit(void) {}

@ -0,0 +1,461 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <xdisplay.h>
#include <SDL.h>
#include <SDL_image.h>
#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(drv->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
display_fb_info_t display_get_frame_buffer(void) {
display_driver_t *drv = &g_display_driver;
#ifdef DISPLAY_MONO
display_fb_info_t fb = {
.ptr = drv->mono_framebuf,
.stride = DISPLAY_RESX,
};
#else
display_fb_info_t fb = {
.ptr = drv->buffer->pixels,
.stride = DISPLAY_RESX * sizeof(uint16_t),
};
#endif
return fb;
}
#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
static 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] > 40 ? 255 : 0;
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
}
#ifndef DISPLAY_MONO
void display_fill(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row =
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
bb_new.dst_stride = drv->buffer->pitch;
gl_rgb565_fill(&bb_new);
}
void display_copy_rgb565(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row =
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
bb_new.dst_stride = drv->buffer->pitch;
gl_rgb565_copy_rgb565(&bb_new);
}
void display_copy_mono1p(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row =
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
bb_new.dst_stride = DISPLAY_RESX;
gl_rgb565_copy_mono1p(&bb_new);
}
void display_copy_mono4(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row =
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
bb_new.dst_stride = drv->buffer->pitch;
gl_rgb565_copy_mono4(&bb_new);
}
#else // DISPLAY_MONO
void display_fill(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = drv->mono_framebuf + (DISPLAY_RESX * bb_new.dst_y);
bb_new.dst_stride = DISPLAY_RESX;
gl_mono8_fill(&bb_new);
}
void display_copy_mono1p(const gl_bitblt_t *bb) {
display_driver_t *drv = &g_display_driver;
gl_bitblt_t bb_new = *bb;
bb_new.dst_row = drv->mono_framebuf + (DISPLAY_RESX * bb_new.dst_y);
bb_new.dst_stride = DISPLAY_RESX;
gl_mono8_copy_mono1p(&bb_new);
}
#endif
const char *display_save(const char *prefix) {
display_driver_t *drv = &g_display_driver;
if (!drv->renderer) {
display_init();
}
#ifdef DISPLAY_MONO
copy_mono_framebuf(drv);
#endif
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;
}

@ -0,0 +1,22 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dma2d_bitblt.h"
void dma2d_wait(void) {}

@ -0,0 +1,152 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_XDISPLAY_H
#define TREZORHAL_XDISPLAY_H
#include <stddef.h>
#include <stdint.h>
#include "gl_bitblt.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 or bootloader 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
typedef struct {
// Pointer to the top-left pixel
void *ptr;
// Stride in bytes
size_t stride;
} display_fb_info_t;
// 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.
display_fb_info_t display_get_frame_buffer(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);
// Sets display to the mode compatible with the legacy bootloader code.
//
// This is used when switching between the firmware and the bootloader.
void display_set_compatible_settings(void);
// Following function define display's bitblt interface.
//
// These functions draw directly to to display or to the
// currently inactive framebuffer.
//
// bb->dst_row and bb->dst_stride must be 0
// Fills a rectangle with a solid color
void display_fill(const gl_bitblt_t *bb);
// Copies an RGB565 bitmap
void display_copy_rgb565(const gl_bitblt_t *bb);
// Copies a MONO4 bitmap
void display_copy_mono4(const gl_bitblt_t *bb);
// Copies a MONO1P bitmap
void display_copy_mono1p(const gl_bitblt_t *bb);
#ifdef TREZOR_EMULATOR
// 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);
#endif
// Adds some declarations needed to compile with the legacy code
// (will be removed with the display legacy code)
#include "xdisplay_legacy.h"
#endif // TREZORHAL_XDISPLAY_H

@ -0,0 +1,43 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "xdisplay_legacy.h"
#include "xdisplay.h"
// This code emulates the legacy display interface and will be
// removed after final cleanup of display drivers when the legacy code
// is removed.
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_sync(void) {}

@ -0,0 +1,56 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_DISPLAY_LEGACY_H
#define TREZORHAL_DISPLAY_LEGACY_H
#include <buffers.h>
#include <stdint.h>
// These declarationscode emulates will be removed after the
// final cleanup of display drivers. They are here just to simplify
// integration with the legacy code.
//
// Most of these function are not called when NEW_RENDERING=1
// and they are only needed to for succesfully code compilation
#define DISPLAY_FRAMEBUFFER_WIDTH 768
#define DISPLAY_FRAMEBUFFER_HEIGHT 480
#define DISPLAY_FRAMEBUFFER_OFFSET_X 0
#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0
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

@ -39,6 +39,7 @@
#include "extmod/misc.h"
#include "extmod/vfs_posix.h"
#include "display.h"
#include "flash.h"
#include "flash_otp.h"
#include "genhdr/mpversion.h"
@ -481,6 +482,8 @@ MP_NOINLINE int main_(int argc, char **argv) {
pre_process_options(argc, argv);
display_init();
// Map trezor.flash to memory.
flash_init();
flash_otp_init();

@ -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_bitblt.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

@ -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,17 @@ def configure(
defines += ["USE_DMA2D", "FRAMEBUFFER", "FRAMEBUFFER32BIT"]
sources += [
"embed/trezorhal/stm32u5/dma2d.c",
"embed/trezorhal/stm32u5/dma2d_bitblt.c",
]
features_available.append("dma2d")
features_available.append("framebuffer")
features_available.append("framebuffer32bit")
if "new_rendering" in features_wanted:
defines += ["XFRAMEBUFFER"]
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 +112,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

@ -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"]
@ -76,4 +86,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

@ -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

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save