diff --git a/core/Makefile b/core/Makefile
index dba27525e..ae74b037f 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -233,18 +233,20 @@ build_embed: build_boardloader build_bootloader build_firmware # build boardload
build_boardloader: ## build boardloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
- CMAKELISTS="$(CMAKELISTS)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin
+ CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin
build_bootloader: ## build bootloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
- CMAKELISTS="$(CMAKELISTS)" BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin
+ CMAKELISTS="$(CMAKELISTS)" BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" \
+ NEW_RENDERING="$(NEW_RENDERING)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin
build_bootloader_ci: ## build CI device testing bootloader
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_CI_BUILD_DIR)/bootloader.bin
build_bootloader_emu: ## build the unix bootloader emulator
- $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf
+ $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
+ CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf
build_prodtest: ## build production test firmware
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
@@ -252,7 +254,7 @@ build_prodtest: ## build production test firmware
build_reflash: ## build reflash firmware + reflash image
$(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \
- CMAKELISTS="$(CMAKELISTS)" $(REFLASH_BUILD_DIR)/reflash.bin
+ CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(REFLASH_BUILD_DIR)/reflash.bin
dd if=build/boardloader/boardloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=0
dd if=build/bootloader/bootloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=49152
@@ -261,24 +263,26 @@ build_firmware: templates build_cross ## build firmware with frozen modules
TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \
PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" \
BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" \
- DISABLE_OPTIGA="$(DISABLE_OPTIGA)" \
+ DISABLE_OPTIGA="$(DISABLE_OPTIGA)" NEW_RENDERING="$(NEW_RENDERING)"\
$(FIRMWARE_BUILD_DIR)/firmware.bin
build_unix: templates ## build unix port
$(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \
TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \
- PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)"
+ PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \
+ NEW_RENDERING="$(NEW_RENDERING)"
build_unix_frozen: templates build_cross ## build unix port with frozen modules
$(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \
TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \
PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \
- TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1
+ TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1 NEW_RENDERING="$(NEW_RENDERING)"
build_unix_debug: templates ## build unix port
$(SCONS) --max-drift=1 CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \
TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \
- BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1
+ BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1 \
+ NEW_RENDERING="$(NEW_RENDERING)"
build_cross: ## build mpy-cross port
$(MAKE) -C vendor/micropython/mpy-cross $(CROSS_PORT_OPTS)
diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader
index a40309ce3..48d4d65a3 100644
--- a/core/SConscript.bootloader
+++ b/core/SConscript.bootloader
@@ -81,21 +81,15 @@ CPPPATH_MOD += [
SOURCE_MOD += [
'embed/extmod/modtrezorcrypto/rand.c',
- 'embed/gdc/gdc_color.c',
- 'embed/gdc/gdc_core.c',
- 'embed/gdc/gdc_mono8_ops.c',
- 'embed/gdc/gdc_rgb565.c',
- 'embed/gdc/gdc_rgb565_ops.c',
- 'embed/gdc/gdc_rgba8888.c',
- 'embed/gdc/gdc_text.c',
- 'embed/gdc/gdc_wnd565.c',
- 'embed/gdc/gdc_wnd565_ops.c',
'embed/lib/buffers.c',
'embed/lib/colors.c',
'embed/lib/display_draw.c',
'embed/lib/display_utils.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
+ 'embed/lib/gl_color.c',
+ 'embed/lib/gl_dma2d_mono8.c',
+ 'embed/lib/gl_dma2d_rgb565.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',
'embed/lib/terminal.c',
diff --git a/core/SConscript.firmware b/core/SConscript.firmware
index 08545e565..989003400 100644
--- a/core/SConscript.firmware
+++ b/core/SConscript.firmware
@@ -13,6 +13,7 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
PYOPT = ARGUMENTS.get('PYOPT', '1')
DISABLE_OPTIGA = ARGUMENTS.get('DISABLE_OPTIGA', '0') == '1'
+NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1'
FEATURE_FLAGS = {
@@ -24,6 +25,8 @@ FEATURE_FLAGS = {
FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"]
if DISABLE_OPTIGA and PYOPT == '0':
FEATURES_WANTED.remove("optiga")
+if NEW_RENDERING:
+ FEATURES_WANTED.append("new_rendering")
CCFLAGS_MOD = ''
CPPPATH_MOD = []
@@ -188,21 +191,14 @@ CPPPATH_MOD += [
]
SOURCE_MOD += [
'embed/extmod/modtrezorui/modtrezorui.c',
- 'embed/gdc/gdc_color.c',
- 'embed/gdc/gdc_core.c',
- 'embed/gdc/gdc_mono8_ops.c',
- 'embed/gdc/gdc_rgb565.c',
- 'embed/gdc/gdc_rgb565_ops.c',
- 'embed/gdc/gdc_rgba8888.c',
- 'embed/gdc/gdc_text.c',
- 'embed/gdc/gdc_wnd565.c',
- 'embed/gdc/gdc_wnd565_ops.c',
'embed/lib/buffers.c',
'embed/lib/colors.c',
- 'embed/lib/display_draw.c',
'embed/lib/display_utils.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
+ 'embed/lib/gl_color.c',
+ 'embed/lib/gl_dma2d_rgb565.c',
+ 'embed/lib/gl_dma2d_mono8.c',
'embed/lib/image.c',
'embed/lib/mini_printf.c',
'embed/lib/terminal.c',
@@ -213,6 +209,17 @@ SOURCE_MOD += [
'vendor/micropython/lib/uzlib/tinflate.c',
]
+if NEW_RENDERING:
+ CPPDEFINES_MOD += ['NEW_RENDERING']
+ SOURCE_MOD += [
+ 'embed/lib/gl_draw.c',
+ ]
+else:
+ SOURCE_MOD += [
+ 'embed/lib/display_draw.c',
+ ]
+
+
CPPDEFINES_MOD += [
'TREZOR_UI2',
'TRANSLATIONS',
@@ -741,11 +748,14 @@ def cargo_build():
features.append('universal_fw')
features.append('ui')
features.append('translations')
- features.append('new_rendering')
+
+ if NEW_RENDERING:
+ features.append('new_rendering')
+
if PYOPT == '0':
features.append('debug')
features.append('ui_debug')
- if TREZOR_MODEL in ('T',):
+ if TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'):
features.append('ui_antialiasing')
features.append('ui_blurring')
features.append('ui_jpeg_decoder')
diff --git a/core/SConscript.unix b/core/SConscript.unix
index 448f3a78d..59ba08c8c 100644
--- a/core/SConscript.unix
+++ b/core/SConscript.unix
@@ -10,6 +10,7 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T')
DMA2D = TREZOR_MODEL in ('T', 'T3T1')
OPTIGA = TREZOR_MODEL in ('R', 'T3T1')
CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0))
+NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1'
if TREZOR_MODEL in ('DISC1', 'DISC2'):
# skip unix build
@@ -190,21 +191,14 @@ CPPPATH_MOD += [
]
SOURCE_MOD += [
'embed/extmod/modtrezorui/modtrezorui.c',
- 'embed/gdc/gdc_color.c',
- 'embed/gdc/gdc_core.c',
- 'embed/gdc/gdc_mono8_ops.c',
- 'embed/gdc/gdc_rgb565.c',
- 'embed/gdc/gdc_rgb565_ops.c',
- 'embed/gdc/gdc_rgba8888.c',
- 'embed/gdc/gdc_text.c',
- 'embed/gdc/gdc_wnd565.c',
- 'embed/gdc/gdc_wnd565_ops.c',
'embed/lib/buffers.c',
'embed/lib/colors.c',
- 'embed/lib/display_draw.c',
'embed/lib/display_utils.c',
'embed/lib/fonts/font_bitmap.c',
'embed/lib/fonts/fonts.c',
+ 'embed/lib/gl_color.c',
+ 'embed/lib/gl_dma2d_rgb565.c',
+ 'embed/lib/gl_dma2d_mono8.c',
'embed/lib/image.c',
'embed/lib/terminal.c',
'embed/lib/translations.c',
@@ -214,6 +208,16 @@ SOURCE_MOD += [
'vendor/micropython/lib/uzlib/tinflate.c',
]
+if NEW_RENDERING:
+ SOURCE_MOD += [
+ 'embed/lib/gl_draw.c',
+ ]
+else:
+ SOURCE_MOD += [
+ 'embed/lib/display_draw.c',
+ ]
+
+
if TREZOR_MODEL in ('1', ):
SOURCE_MOD += [
'embed/models/model_T1B1_layout.c',
@@ -247,6 +251,17 @@ if FROZEN:
if RASPI:
CPPDEFINES_MOD += ['TREZOR_EMULATOR_RASPI']
+if NEW_RENDERING:
+ CPPDEFINES_MOD += ['NEW_RENDERING']
+ if TREZOR_MODEL in ('T',):
+ CPPDEFINES_MOD += ['DISPLAY_RGB565']
+ elif TREZOR_MODEL in ('R', '1',):
+ CPPDEFINES_MOD += ['XFRAMEBUFFER', 'DISPLAY_MONO']
+ elif TREZOR_MODEL in ('T3T1',):
+ CPPDEFINES_MOD += ['XFRAMEBUFFER', 'DISPLAY_RGB565']
+
+
+
# modtrezorutils
SOURCE_MOD += [
'embed/extmod/modtrezorutils/modtrezorutils.c',
@@ -391,7 +406,6 @@ SOURCE_MICROPYTHON = [
SOURCE_UNIX = [
'embed/trezorhal/unix/boot_args.c',
'embed/trezorhal/unix/common.c',
- 'embed/trezorhal/unix/display-unix.c',
'embed/trezorhal/unix/flash.c',
'embed/trezorhal/unix/flash_otp.c',
'embed/trezorhal/unix/random_delays.c',
@@ -407,6 +421,18 @@ SOURCE_UNIX = [
'vendor/micropython/ports/unix/input.c',
'vendor/micropython/ports/unix/unix_mphal.c',
]
+
+if NEW_RENDERING:
+ SOURCE_MOD += [
+ 'embed/trezorhal/unix/display_driver.c',
+ 'embed/trezorhal/xdisplay_legacy.c',
+ ]
+else:
+ SOURCE_MOD += [
+ 'embed/trezorhal/unix/display-unix.c',
+ ]
+
+
if TREZOR_MODEL in ('T', 'R', 'T3T1'):
SOURCE_UNIX += [
'embed/trezorhal/unix/sbu.c',
@@ -421,6 +447,7 @@ if DMA2D:
CPPDEFINES_MOD += [
'USE_DMA2D',
]
+
SOURCE_UNIX += [
'embed/lib/dma2d_emul.c',
]
@@ -830,7 +857,6 @@ def cargo_build():
features.append('universal_fw')
features.append('ui')
features.append('translations')
- features.append('new_rendering')
if PYOPT == '0':
features.append('debug')
if DMA2D:
@@ -845,6 +871,18 @@ def cargo_build():
if TREZOR_MODEL in ('R', '1'):
features.append('button')
+
+ if NEW_RENDERING:
+ features.append('new_rendering')
+ if TREZOR_MODEL in ('T',):
+ features.append('display_rgb565')
+ elif TREZOR_MODEL in ('R', '1',):
+ features.append('display_mono')
+ features.append('xframebuffer')
+ elif TREZOR_MODEL in ('T3T1',):
+ features.append('display_rgb565')
+ features.append('xframebuffer')
+
env.get('ENV')['TREZOR_MODEL'] = TREZOR_MODEL
return f'cd embed/rust; cargo build --profile {RUST_PROFILE} --target-dir=../../build/unix/rust --no-default-features --features "{" ".join(features)}" --target {TARGET}'
diff --git a/core/embed/extmod/modtrezorui/modtrezorui-display.h b/core/embed/extmod/modtrezorui/modtrezorui-display.h
index 85662585a..c06a4d2f3 100644
--- a/core/embed/extmod/modtrezorui/modtrezorui-display.h
+++ b/core/embed/extmod/modtrezorui/modtrezorui-display.h
@@ -18,6 +18,8 @@
*/
#include "display.h"
+#include "display_draw.h"
+#include "fonts/fonts.h"
/// class Display:
/// """
diff --git a/core/embed/gdc/gdc_bitmap.h b/core/embed/gdc/gdc_bitmap.h
deleted file mode 100644
index 842f32011..000000000
--- a/core/embed/gdc/gdc_bitmap.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef GDC_BITMAP_H
-#define GDC_BITMAP_H
-
-#include "gdc_color.h"
-#include "gdc_geom.h"
-
-#include
-#include
-
-// forward declaration
-typedef struct gdc_vmt gdc_vmt_t;
-
-// ------------------------------------------------------------------------
-// GDC Bitmap pixel format
-//
-
-typedef enum {
- GDC_FORMAT_UNKNOWN, //
- GDC_FORMAT_MONO1, // 1-bpp per pixel
- GDC_FORMAT_MONO4, // 4-bpp per pixel
- GDC_FORMAT_RGB565, // 16-bpp per pixel
- GDC_FORMAT_RGBA8888, // 32-bpp
-
-} gdc_format_t;
-
-// ------------------------------------------------------------------------
-// GDC Bitmap Attributes
-//
-
-#define GDC_BITMAP_READ_ONLY 0x01 // Read-only data
-// #define GDC_BITMAP_DMA_READ 0x02 // DMA read pending
-// #define GDC_BITMAP_DMA_WRITE 0x04 // DMA write pending
-
-// ------------------------------------------------------------------------
-// GDC Bitmap
-//
-// Structure holding pointer to the bitmap data, its format and sizes
-//
-// Note: gdc_bitmap_t itself can be used as GDC as long as it contains
-// valid gdc virtual table pointer.
-
-typedef struct gdc_bitmap {
- // GDC virtual method table
- // (must be the first field of the structure)
- const gdc_vmt_t* vmt;
- // pointer to top-left pixel
- void* ptr;
- // stride in bytes
- size_t stride;
- // size in pixels
- gdc_size_t size;
- // format of pixels, GDC_FORMAT_xxx
- uint8_t format;
- // attributes, GDC_BITMAP_xxx
- uint8_t attrs;
-
-} gdc_bitmap_t;
-
-// Initializes RGB565 bitmap structure
-// GDC and format fields and filled automatically.
-gdc_bitmap_t gdc_bitmap_rgb565(void* data_ptr, size_t stride, gdc_size_t size,
- uint8_t attrs);
-
-// Initializes RGBA8888 bitmap structure
-// GDC and format fields and filled automatically.
-gdc_bitmap_t gdc_bitmap_rgba8888(void* data_ptr, size_t stride, gdc_size_t size,
- uint8_t attrs);
-
-// ------------------------------------------------------------------------
-// GDC Bitmap reference
-//
-// Structure is used when bitmap is beeing drawed to supply
-// additional parameters
-
-typedef struct {
- // soruce bitmap
- const gdc_bitmap_t* bitmap;
- // offset used when bitmap is drawed on gdc
- gdc_offset_t offset;
- // foreground color (used with MONOx formats)
- gdc_color_t fg_color;
- // background color (used with MONOx formats)
- gdc_color_t bg_color;
-
-} gdc_bitmap_ref_t;
-
-#endif // GDC_BITMAP_H
diff --git a/core/embed/gdc/gdc_clip.h b/core/embed/gdc/gdc_clip.h
deleted file mode 100644
index daa250bed..000000000
--- a/core/embed/gdc/gdc_clip.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef GDC_CLIP_H
-#define GDC_CLIP_H
-
-#include
-#include "gdc.h"
-
-typedef struct {
- int16_t dst_x;
- int16_t dst_y;
- int16_t src_x;
- int16_t src_y;
- int16_t width;
- int16_t height;
-} gdc_clip_t;
-
-static inline gdc_clip_t gdc_clip(gdc_rect_t dst, gdc_size_t size,
- const gdc_bitmap_ref_t* src) {
- int16_t dst_x = dst.x0;
- int16_t dst_y = dst.y0;
-
- int16_t src_x = 0;
- int16_t src_y = 0;
-
- if (src != NULL) {
- src_x += src->offset.x;
- src_y += src->offset.y;
-
- // Normalize negative x-offset of src bitmap
- if (src_x < 0) {
- dst_x -= src_x;
- src_x = 0;
- }
-
- // Normalize negative y-offset of src bitmap
- if (src_y < 0) {
- dst_y -= src_y;
- src_y = 0;
- }
- }
-
- // Normalize negative top-left of destination rectangle
- if (dst_x < 0) {
- src_x -= dst_x;
- dst_x = 0;
- }
-
- if (dst_y < 0) {
- src_y -= dst_y;
- dst_y = 0;
- }
-
- // Calculate dimension of effective rectangle
- int16_t width = MIN(size.x, dst.x1) - dst_x;
- int16_t height = MIN(size.y, dst.y1) - dst_y;
-
- if (src != NULL) {
- width = MIN(width, src->bitmap->size.x - src_x);
- height = MIN(height, src->bitmap->size.y - src_y);
- }
-
- gdc_clip_t clip = {
- .dst_x = dst_x,
- .dst_y = dst_y,
- .src_x = src_x,
- .src_y = src_y,
- .width = width,
- .height = height,
- };
-
- return clip;
-}
-
-#endif // GDC_CLIP_H
diff --git a/core/embed/gdc/gdc_core.c b/core/embed/gdc/gdc_core.c
deleted file mode 100644
index 4eabecf9a..000000000
--- a/core/embed/gdc/gdc_core.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "gdc_core.h"
-#include "gdc_clip.h"
-
-#include "dma2d.h"
-
-void gdc_release(gdc_t* gdc) {
- if (gdc != NULL) {
- gdc_wait_for_pending_ops(gdc);
-
- gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
- if (vmt != NULL && vmt->release != NULL) {
- vmt->release(gdc);
- }
- }
-}
-
-gdc_size_t gdc_get_size(const gdc_t* gdc) {
- if (gdc != NULL) {
- gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
- if (vmt != NULL && vmt->get_bitmap != NULL) {
- return vmt->get_bitmap((gdc_t*)gdc)->size;
- }
- }
-
- return gdc_size(0, 0);
-}
-
-void gdc_wait_for_pending_ops(gdc_t* gdc) {
-#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
- if (gdc != NULL) {
- dma2d_wait();
- }
-#endif
-}
-
-bool gdc_fill_rect(gdc_t* gdc, gdc_rect_t rect, gdc_color_t color) {
- if (gdc != NULL) {
- gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
-
- gdc_bitmap_t* bitmap = (gdc_bitmap_t*)gdc;
-
- gdc_clip_t clip = gdc_clip(rect, bitmap->size, NULL);
-
- if (clip.width <= 0 || clip.height <= 0) {
- return true;
- }
-
- dma2d_params_t dp = {
- // Destination bitmap
- .height = clip.height,
- .width = clip.width,
- .dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y,
- .dst_x = clip.dst_x,
- .dst_y = clip.dst_y,
- .dst_stride = bitmap->stride,
-
- // Source bitmap
- .src_fg = color,
- .src_alpha = 255,
- };
-
- gdc_wait_for_pending_ops(gdc);
-
- if (vmt->fill != NULL) {
- return vmt->fill(gdc, &dp);
- }
- }
-
- return false;
-}
-
-bool gdc_draw_bitmap(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src) {
- if (gdc != NULL) {
- gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
-
- gdc_bitmap_t* bitmap = vmt->get_bitmap(gdc);
-
- gdc_clip_t clip = gdc_clip(rect, bitmap->size, src);
-
- if (clip.width <= 0 || clip.height <= 0) {
- return true;
- }
-
- dma2d_params_t dp = {
- // Destination bitmap
- .height = clip.height,
- .width = clip.width,
- .dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y,
- .dst_x = clip.dst_x,
- .dst_y = clip.dst_y,
- .dst_stride = bitmap->stride,
-
- // Source bitmap
- .src_row =
- (uint8_t*)src->bitmap->ptr + src->bitmap->stride * clip.src_y,
- .src_x = clip.src_x,
- .src_y = clip.src_y,
- .src_stride = src->bitmap->stride,
- .src_fg = src->fg_color,
- .src_bg = src->bg_color,
- .src_alpha = 255,
- };
-
- gdc_wait_for_pending_ops(gdc);
-
- if (src->bitmap->format == GDC_FORMAT_MONO4) {
- if (vmt->copy_mono4 != NULL) {
- return vmt->copy_mono4(gdc, &dp);
- }
- } else if (src->bitmap->format == GDC_FORMAT_RGB565) {
- if (vmt->copy_rgb565 != NULL) {
- return vmt->copy_rgb565(gdc, &dp);
- }
- } else if (src->bitmap->format == GDC_FORMAT_RGBA8888) {
- if (vmt->copy_rgba8888 != NULL) {
- return vmt->copy_rgba8888(gdc, &dp);
- }
- }
- }
-
- return false;
-}
-
-bool gdc_draw_blended(gdc_t* gdc, gdc_rect_t rect,
- const gdc_bitmap_ref_t* src) {
- if (gdc != NULL) {
- gdc_vmt_t* vmt = *(gdc_vmt_t**)gdc;
-
- gdc_bitmap_t* bitmap = vmt->get_bitmap(gdc);
-
- gdc_clip_t clip = gdc_clip(rect, bitmap->size, src);
-
- if (clip.width <= 0 || clip.height <= 0) {
- return true;
- }
-
- dma2d_params_t dp = {
- // Destination rectangle
- .height = clip.height,
- .width = clip.width,
- .dst_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.dst_y,
- .dst_x = clip.dst_x,
- .dst_y = clip.dst_y,
- .dst_stride = bitmap->stride,
-
- // Source bitmap
- .src_row =
- (uint8_t*)src->bitmap->ptr + src->bitmap->stride * clip.src_y,
- .src_x = clip.src_x,
- .src_y = clip.src_y,
- .src_stride = src->bitmap->stride,
- .src_fg = src->fg_color,
- .src_alpha = 255,
- };
-
- gdc_wait_for_pending_ops(gdc);
-
- if (src->bitmap->format == GDC_FORMAT_MONO4) {
- if (vmt->blend_mono4 != NULL) {
- return vmt->blend_mono4(gdc, &dp);
- }
- }
- }
-
- return false;
-}
diff --git a/core/embed/gdc/gdc_core.h b/core/embed/gdc/gdc_core.h
deleted file mode 100644
index 7c8b97beb..000000000
--- a/core/embed/gdc/gdc_core.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef GDC_CORE_H
-#define GDC_CORE_H
-
-#include "gdc_bitmap.h"
-#include "gdc_color.h"
-#include "gdc_dma2d.h"
-#include "gdc_geom.h"
-
-#include
-#include
-#include
-
-// ------------------------------------------------------------------------
-// GDC - Graphics Device Context
-//
-
-typedef void gdc_t;
-
-// ------------------------------------------------------------------------
-// GDC (Graphic Device Context) Virtual Method Table
-//
-// GDC structure is implementation specific. Only requirement is that
-// it starts with a field of type gdc_vmt_t* vmt.
-//
-// typedef struct
-// {
-// gdc_vmt_t* vmt;
-//
-// // GDC specific data
-//
-// } gdc_impl_specific_t;
-//
-
-typedef void (*gdc_release_t)(gdc_t* gdc);
-typedef gdc_bitmap_t* (*gdc_get_bitmap_t)(gdc_t* gdc);
-typedef bool (*gdc_fill_t)(gdc_t* gdc, dma2d_params_t* params);
-typedef bool (*gdc_copy_mono4_t)(gdc_t* gdc, dma2d_params_t* params);
-typedef bool (*gdc_copy_rgb565_t)(gdc_t* gdc, dma2d_params_t* params);
-typedef bool (*gdc_copy_rgba8888_t)(gdc_t* gdc, dma2d_params_t* params);
-typedef bool (*gdc_blend_mono4_t)(gdc_t* gdc, dma2d_params_t* params);
-
-// GDC virtual methods
-struct gdc_vmt {
- gdc_release_t release;
- gdc_get_bitmap_t get_bitmap;
- gdc_fill_t fill;
- gdc_copy_mono4_t copy_mono4;
- gdc_copy_rgb565_t copy_rgb565;
- gdc_copy_rgba8888_t copy_rgba8888;
- gdc_blend_mono4_t blend_mono4;
-};
-
-// ------------------------------------------------------------------------
-// GDC (Graphic Device Context) Public API
-
-// Releases reference to GDC
-void gdc_release(gdc_t* gdc);
-
-// Gets size of GDC bounding rectangle
-gdc_size_t gdc_get_size(const gdc_t* gdc);
-
-// Wait for pending DMA operation applied on this GDC
-// (used by high level code before accessing GDC's framebuffer/bitmap)
-void gdc_wait_for_pending_ops(gdc_t* gdc);
-
-// Fills a rectangle with a specified color
-bool gdc_fill_rect(gdc_t* gdc, gdc_rect_t rect, gdc_color_t color);
-
-// Draws a bitmap into the specified rectangle
-// The destination rectangle may not be fully filled if the source bitmap
-// is smaller then destination rectangle or if the bitmap is translated by
-// an offset partially or completely outside the destination rectangle.
-bool gdc_draw_bitmap(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src);
-
-// Blends a bitmap with the gdc background in the specified rectangle.
-// The destination rectangle may not be fully filled if the source bitmap
-// is smaller then destination rectangle or if the bitmap is translated by
-// an offset partially or completely outside the destination rectangle.
-bool gdc_draw_blended(gdc_t* gdc, gdc_rect_t rect, const gdc_bitmap_ref_t* src);
-
-// ------------------------------------------------------------------------
-// this will be defined elsewhere::
-
-// Gets GDC for the hardware display
-// Returns NULL if display gdc was already acquired and not released
-gdc_t* display_acquire_gdc(void);
-
-#endif // GDC_CORE_H
diff --git a/core/embed/gdc/gdc_geom.h b/core/embed/gdc/gdc_geom.h
deleted file mode 100644
index 2ffd11c0c..000000000
--- a/core/embed/gdc/gdc_geom.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef GDC_GEOM_H
-#define GDC_GEOM_H
-
-// ------------------------------------------------------------------------
-// GDC Rectangle
-//
-// used for simplified manipulation with rectangle coordinates
-
-typedef struct {
- int16_t x0;
- int16_t y0;
- int16_t x1;
- int16_t y1;
-} gdc_rect_t;
-
-// Creates a rectangle from top-left coordinates and dimensions
-static inline gdc_rect_t gdc_rect_wh(int16_t x, int16_t y, int16_t w,
- int16_t h) {
- gdc_rect_t rect = {
- .x0 = x,
- .y0 = y,
- .x1 = x + w,
- .y1 = y + h,
- };
-
- return rect;
-}
-
-// Creates a rectangle from top-left and bottom-right coordinates
-static inline gdc_rect_t gdc_rect(int16_t x0, int16_t y0, int16_t x1,
- int16_t y1) {
- gdc_rect_t rect = {
- .x0 = x0,
- .y0 = y0,
- .x1 = x1,
- .y1 = y1,
- };
-
- return rect;
-}
-
-// ------------------------------------------------------------------------
-// GDC Size
-//
-// used for simplified manipulation with size of objects
-
-typedef struct {
- int16_t x;
- int16_t y;
-} gdc_size_t;
-
-// Creates a rectangle from top-left and bottom-right coordinates
-static inline gdc_size_t gdc_size(int16_t x, int16_t y) {
- gdc_size_t size = {
- .x = x,
- .y = y,
- };
-
- return size;
-}
-
-// ------------------------------------------------------------------------
-// GDC Offset
-//
-// used for simplified manipulation with size of objects
-
-typedef gdc_size_t gdc_offset_t;
-
-#endif // GDC_GEOM_H
diff --git a/core/embed/gdc/gdc_rgb565.c b/core/embed/gdc/gdc_rgb565.c
deleted file mode 100644
index 72bce2002..000000000
--- a/core/embed/gdc/gdc_rgb565.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "gdc_core.h"
-#include "gdc_dma2d.h"
-#include "gdc_ops.h"
-
-#include
-
-static void gdc_rgb565_release(gdc_t* gdc) {
- /* gdc_bitmap_t* bitmap = (gdc_bitmap_t*) gdc;
-
- if (bitmap->release != NULL) {
- bitmap->release(bitmap->context);
- }*/
-}
-
-static gdc_bitmap_t* gdc_rgb565_get_bitmap(gdc_t* gdc) {
- return (gdc_bitmap_t*)gdc;
-}
-
-static bool gdc_rgb565_fill(gdc_t* gdc, dma2d_params_t* params) {
- return rgb565_fill(params);
-}
-
-static bool gdc_rgb565_copy_mono4(gdc_t* gdc, dma2d_params_t* params) {
- return rgb565_copy_mono4(params);
-}
-
-static bool gdc_rgb565_copy_rgb565(gdc_t* gdc, dma2d_params_t* params) {
- return rgb565_copy_rgb565(params);
-}
-
-static bool gdc_rgb565_blend_mono4(gdc_t* gdc, dma2d_params_t* params) {
- return rgb565_blend_mono4(params);
-}
-
-gdc_bitmap_t gdc_bitmap_rgb565(void* data_ptr, size_t stride, gdc_size_t size,
- uint8_t attrs) {
- static const gdc_vmt_t gdc_rgb565 = {
- .release = gdc_rgb565_release,
- .get_bitmap = gdc_rgb565_get_bitmap,
- .fill = gdc_rgb565_fill,
- .copy_mono4 = gdc_rgb565_copy_mono4,
- .copy_rgb565 = gdc_rgb565_copy_rgb565,
- .copy_rgba8888 = NULL,
- .blend_mono4 = gdc_rgb565_blend_mono4,
- };
-
- gdc_bitmap_t bitmap = {.vmt = &gdc_rgb565,
- .ptr = data_ptr,
- .stride = stride,
- .size = size,
- .format = GDC_FORMAT_RGB565,
- .attrs = attrs};
-
- return bitmap;
-}
diff --git a/core/embed/gdc/gdc_rgba8888.c b/core/embed/gdc/gdc_rgba8888.c
deleted file mode 100644
index f4481816d..000000000
--- a/core/embed/gdc/gdc_rgba8888.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "gdc_core.h"
-
-#include
-
-static void gdc_rgba8888_release(gdc_t* gdc) {
- /* gdc_bitmap_t* bitmap = (gdc_bitmap_t*) gdc;
-
- if (bitmap->release != NULL) {
- bitmap->release(bitmap->context);
- }*/
-}
-
-static gdc_bitmap_t* gdc_rgba8888_get_bitmap(gdc_t* gdc) {
- return (gdc_bitmap_t*)gdc;
-}
-
-gdc_bitmap_t gdc_bitmap_rgba8888(void* data_ptr, size_t stride, gdc_size_t size,
- uint8_t attrs) {
- static const gdc_vmt_t gdc_rgba8888 = {
- .release = gdc_rgba8888_release,
- .get_bitmap = gdc_rgba8888_get_bitmap,
- .fill = NULL, // dma2d_rgba8888_fill,
- .copy_mono4 = NULL, // dma2d_rgba8888_copy_mono4,
- .copy_rgb565 = NULL, // dma2d_rgba8888_copy_rgb565,
- .copy_rgba8888 = NULL, // dma2d_rgba8888_copy_rgba8888,
- .blend_mono4 = NULL, // dma2d_rgba8888_blend_mono4_mono4,
- };
-
- gdc_bitmap_t bitmap = {
- .vmt = &gdc_rgba8888,
- .ptr = data_ptr,
- .stride = stride,
- .size = size,
- .format = GDC_FORMAT_RGBA8888,
- .attrs = attrs,
- };
-
- return bitmap;
-}
diff --git a/core/embed/gdc/gdc_text.c b/core/embed/gdc/gdc_text.c
deleted file mode 100644
index 3d98e9501..000000000
--- a/core/embed/gdc/gdc_text.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "gdc_text.h"
-
-#include "fonts/fonts.h"
-
-#if TREZOR_FONT_BPP == 1
-#define GLYPH_FORMAT GDC_FORMAT_MONO1
-#define GLYPH_STRIDE(w) (((w) + 7) / 8)
-#elif TREZOR_FONT_BPP == 2
-#error Unsupported TREZOR_FONT_BPP value
-#define GLYPH_FORMAT GDC_FORMAT_MONO2
-#define GLYPH_STRIDE(w) (((w) + 3) / 4)
-#elif TREZOR_FONT_BPP == 4
-#define GLYPH_FORMAT GDC_FORMAT_MONO4
-#define GLYPH_STRIDE(w) (((w) + 1) / 2)
-#elif TREZOR_FONT_BPP == 8
-#error Unsupported TREZOR_FONT_BPP value
-#define GLYPH_FORMAT GDC_FORMAT_MONO8
-#define GLYPH_STRIDE(w) (w)
-#else
-#error Unsupported TREZOR_FONT_BPP value
-#endif
-
-#define GLYPH_WIDTH(g) ((g)[0])
-#define GLYPH_HEIGHT(g) ((g)[1])
-#define GLYPH_ADVANCE(g) ((g)[2])
-#define GLYPH_BEARING_X(g) ((g)[3])
-#define GLYPH_BEARING_Y(g) ((g)[4])
-#define GLYPH_DATA(g) ((void*)&(g)[5])
-
-bool gdc_draw_opaque_text(gdc_t* gdc, gdc_rect_t rect, const char* text,
- size_t maxlen, const gdc_text_attr_t* attr) {
- if (text == NULL) {
- return false;
- }
-
- gdc_bitmap_t glyph_bitmap;
- glyph_bitmap.vmt = NULL;
- glyph_bitmap.format = GLYPH_FORMAT;
-
- gdc_bitmap_ref_t glyph_ref;
- glyph_ref.bitmap = &glyph_bitmap;
- glyph_ref.fg_color = attr->fg_color;
- glyph_ref.bg_color = attr->bg_color;
-
- int max_height = font_max_height(attr->font);
- int baseline = font_baseline(attr->font);
-
- int offset_x = attr->offset.x;
-
- if (offset_x < 0) {
- rect.x0 -= attr->offset.x;
- offset_x = 0;
- }
-
- for (int i = 0; i < maxlen; i++) {
- uint8_t ch = (uint8_t)text[i];
-
- if (ch == 0 || rect.x0 >= rect.x1) {
- break;
- }
-
- const uint8_t* glyph = font_get_glyph(attr->font, ch);
-
- if (glyph == NULL) {
- continue;
- }
-
- if (offset_x >= GLYPH_ADVANCE(glyph)) {
- offset_x -= GLYPH_ADVANCE(glyph);
- continue;
- }
-
- glyph_bitmap.ptr = GLYPH_DATA(glyph);
- glyph_bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
- glyph_bitmap.size.x = GLYPH_WIDTH(glyph);
- glyph_bitmap.size.y = GLYPH_HEIGHT(glyph);
-
- glyph_ref.offset.x = attr->offset.x - GLYPH_BEARING_X(glyph);
- glyph_ref.offset.y =
- attr->offset.y - (max_height - baseline - GLYPH_BEARING_Y(glyph));
-
- if (!gdc_draw_bitmap(gdc, rect, &glyph_ref)) {
- return false;
- }
-
- rect.x0 += GLYPH_ADVANCE(glyph) - offset_x;
- offset_x = 0;
- }
-
- return true;
-}
-
-bool gdc_draw_blended_text(gdc_t* gdc, gdc_rect_t rect, const char* text,
- size_t maxlen, const gdc_text_attr_t* attr) {
- if (text == NULL) {
- return false;
- }
-
- gdc_bitmap_t glyph_bitmap;
- glyph_bitmap.vmt = NULL;
- glyph_bitmap.format = GLYPH_FORMAT;
-
- gdc_bitmap_ref_t glyph_ref;
- glyph_ref.bitmap = &glyph_bitmap;
- glyph_ref.fg_color = attr->fg_color;
- glyph_ref.bg_color = attr->bg_color;
-
- int max_height = font_max_height(attr->font);
- int baseline = font_baseline(attr->font);
-
- int offset_x = attr->offset.x;
-
- if (offset_x < 0) {
- rect.x0 -= attr->offset.x;
- offset_x = 0;
- }
-
- for (int i = 0; i < maxlen; i++) {
- uint8_t ch = (uint8_t)text[i];
-
- if (ch == 0 || rect.x0 >= rect.x1) {
- break;
- }
-
- const uint8_t* glyph = font_get_glyph(attr->font, ch);
-
- if (glyph == NULL) {
- continue;
- }
-
- if (offset_x >= GLYPH_ADVANCE(glyph)) {
- offset_x -= GLYPH_ADVANCE(glyph);
- continue;
- } else {
- }
-
- glyph_bitmap.ptr = GLYPH_DATA(glyph);
- glyph_bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
- glyph_bitmap.size.x = GLYPH_WIDTH(glyph);
- glyph_bitmap.size.y = GLYPH_HEIGHT(glyph);
-
- glyph_ref.offset.x = offset_x - GLYPH_BEARING_X(glyph);
- glyph_ref.offset.y =
- attr->offset.y - (max_height - baseline - GLYPH_BEARING_Y(glyph));
-
- if (!gdc_draw_blended(gdc, rect, &glyph_ref)) {
- return false;
- }
-
- rect.x0 += GLYPH_ADVANCE(glyph) - offset_x;
- offset_x = 0;
- }
-
- return true;
-}
diff --git a/core/embed/gdc/gdc_wnd565.c b/core/embed/gdc/gdc_wnd565.c
deleted file mode 100644
index 6e008ea81..000000000
--- a/core/embed/gdc/gdc_wnd565.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "gdc_wnd565.h"
-#include "gdc_ops.h"
-
-#include
-
-#include "display.h"
-
-static void gdc_wnd565_release(gdc_t* gdc) {
- // gdc_wnd565_t* wnd = (gdc_wnd565_t*)gdc;
-
- // if (wnd->config.release != NULL) {
- // wnd->config.release(wnd->config.context);
- // }
-}
-
-static gdc_bitmap_t* gdc_wnd565_get_bitmap(gdc_t* gdc) {
- return &((gdc_wnd565_t*)gdc)->bitmap;
-}
-
-static bool gdc_wnd565_fill(gdc_t* gdc, dma2d_params_t* params) {
- return wnd565_fill(params);
-}
-
-static bool gdc_wnd565_copy_rgb565(gdc_t* gdc, dma2d_params_t* params) {
- return wnd565_copy_rgb565(params);
-}
-
-gdc_t* gdc_wnd565_init(gdc_wnd565_t* gdc, gdc_wnd565_config_t* config) {
- static const gdc_vmt_t gdc_wnd565 = {
- .release = gdc_wnd565_release,
- .get_bitmap = gdc_wnd565_get_bitmap,
- .fill = gdc_wnd565_fill,
- .copy_mono4 = NULL, // gdc_wnd565_copy_mono4,
- .copy_rgb565 = gdc_wnd565_copy_rgb565,
- .copy_rgba8888 = NULL,
- .blend_mono4 = NULL,
- };
-
- memset(gdc, 0, sizeof(gdc_wnd565_t));
- gdc->vmt = &gdc_wnd565;
- gdc->bitmap.format = GDC_FORMAT_RGB565;
- gdc->bitmap.size = config->size;
- gdc->bitmap.ptr = (void*)config->reg_address;
-
- return (gdc_t*)&gdc->vmt;
-}
-
-gdc_t* display_acquire_gdc(void) {
- static gdc_wnd565_t wnd = {};
-
- if (wnd.vmt == NULL) {
- gdc_wnd565_config_t config = {
- .size.x = 240,
- .size.y = 240,
- };
- gdc_wnd565_init(&wnd, &config);
- }
-
- return (gdc_t*)&wnd.vmt;
-}
diff --git a/core/embed/gdc/gdc_wnd565.h b/core/embed/gdc/gdc_wnd565.h
deleted file mode 100644
index e55bfb883..000000000
--- a/core/embed/gdc/gdc_wnd565.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#ifndef GDC_WND565_H
-#define GDC_WND565_H
-
-#include "gdc_core.h"
-
-// ------------------------------------------------------------------------
-// GDC for displays RGB565 with register/window API like ST7789
-//
-// This module serves as a driver for specific types of displays with
-// internal memory acting as a frame buffer and a specific interface
-// for writing to this framebuffer by putting pixels into the
-// specified rectangle window.
-
-typedef void (*gdc_release_cb_t)(void* context);
-
-// Driver configuration
-typedef struct {
- // TODO
- uintptr_t reg_address;
-
- // GDC size in pixels
- gdc_size_t size;
-
- // Release callback invoked when gdc_release() is called
- gdc_release_cb_t release;
- // Context for release callback
- void* context;
-
-} gdc_wnd565_config_t;
-
-// Driver-specific GDC structure
-typedef struct {
- // GDC virtual method table
- // (Must be the first field of the structure)
- const gdc_vmt_t* vmt;
-
- // Fake bitmap structure
- gdc_bitmap_t bitmap;
-
- // Current drawing window/rectangle
- gdc_rect_t rect;
- // Cursor position in the window
- int cursor_x;
- int cursor_y;
-
-} gdc_wnd565_t;
-
-// Initializes GDC context
-gdc_t* gdc_wnd565_init(gdc_wnd565_t* gdc, gdc_wnd565_config_t* config);
-
-#endif // GDC_WND565_H
diff --git a/core/embed/gdc/gdc_wnd565_ops.c b/core/embed/gdc/gdc_wnd565_ops.c
deleted file mode 100644
index d894f7316..000000000
--- a/core/embed/gdc/gdc_wnd565_ops.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * This file is part of the Trezor project, https://trezor.io/
- *
- * Copyright (c) SatoshiLabs
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-#include "gdc_ops.h"
-
-#include "display.h"
-
-static void set_window(const dma2d_params_t* dp) {
- display_set_window(dp->dst_x, dp->dst_y, dp->dst_x + dp->width - 1,
- dp->dst_y + dp->height + 1);
-}
-
-bool wnd565_fill(const dma2d_params_t* dp) {
- set_window(dp);
-
- uint16_t height = dp->height;
-
- while (height-- > 0) {
- for (int x = 0; x < dp->width; x++) {
- PIXELDATA(dp->src_fg);
- }
- }
-
- return true;
-}
-
-bool wnd565_copy_rgb565(const dma2d_params_t* dp) {
- set_window(dp);
-
- uint16_t* src_ptr = (uint16_t*)dp->src_row + dp->src_x;
- uint16_t height = dp->height;
-
- while (height-- > 0) {
- for (int x = 0; x < dp->width; x++) {
- PIXELDATA(src_ptr[x]);
- }
- src_ptr += dp->src_stride / sizeof(*src_ptr);
- }
-
- return true;
-}
diff --git a/core/embed/lib/display_draw.c b/core/embed/lib/display_draw.c
index 608fabe42..138155ebb 100644
--- a/core/embed/lib/display_draw.c
+++ b/core/embed/lib/display_draw.c
@@ -61,8 +61,8 @@ void display_clear(void) {
// set MADCTL first so that we can set the window correctly next
display_orientation(0);
// address the complete frame memory
- display_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1);
- for (uint32_t i = 0; i < MAX_DISPLAY_RESX * MAX_DISPLAY_RESY; i++) {
+ display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
+ for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
// 2 bytes per pixel because we're using RGB 5-6-5 format
PIXELDATA(0x0000);
}
diff --git a/core/embed/gdc/gdc_color.c b/core/embed/lib/gl_color.c
similarity index 52%
rename from core/embed/gdc/gdc_color.c
rename to core/embed/lib/gl_color.c
index 6ebbf94c3..ec943ad4b 100644
--- a/core/embed/gdc/gdc_color.c
+++ b/core/embed/lib/gl_color.c
@@ -17,33 +17,33 @@
* along with this program. If not, see .
*/
-#include "gdc_color.h"
+#include "gl_color.h"
#include "colors.h"
-const gdc_color16_t* gdc_color16_gradient_a4(gdc_color_t fg_color,
- gdc_color_t bg_color) {
- static gdc_color16_t cache[16] = {0};
+const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg_color,
+ gl_color_t bg_color) {
+ static gl_color16_t cache[16] = {0};
- if (gdc_color_to_color16(bg_color) != cache[0] ||
- gdc_color_to_color16(fg_color) != cache[15]) {
+ if (gl_color_to_color16(bg_color) != cache[0] ||
+ gl_color_to_color16(fg_color) != cache[15]) {
for (int alpha = 0; alpha < 16; alpha++) {
- cache[alpha] = gdc_color16_blend_a4(fg_color, bg_color, alpha);
+ cache[alpha] = gl_color16_blend_a4(fg_color, bg_color, alpha);
}
}
- return (const gdc_color16_t*)&cache[0];
+ return (const gl_color16_t*)&cache[0];
}
-const gdc_color32_t* gdc_color32_gradient_a4(gdc_color_t fg_color,
- gdc_color_t bg_color) {
- static gdc_color32_t cache[16] = {0};
+const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg_color,
+ gl_color_t bg_color) {
+ static gl_color32_t cache[16] = {0};
- if (bg_color != gdc_color32_to_color(cache[0]) ||
- fg_color != gdc_color32_to_color(cache[15])) {
+ if (bg_color != gl_color32_to_color(cache[0]) ||
+ fg_color != gl_color32_to_color(cache[15])) {
for (int alpha = 0; alpha < 16; alpha++) {
- cache[alpha] = gdc_color32_blend_a4(fg_color, bg_color, alpha);
+ cache[alpha] = gl_color32_blend_a4(fg_color, bg_color, alpha);
}
}
- return (const gdc_color32_t*)&cache[0];
+ return (const gl_color32_t*)&cache[0];
}
\ No newline at end of file
diff --git a/core/embed/gdc/gdc_color.h b/core/embed/lib/gl_color.h
similarity index 72%
rename from core/embed/gdc/gdc_color.h
rename to core/embed/lib/gl_color.h
index fb670fde5..83d25a251 100644
--- a/core/embed/gdc/gdc_color.h
+++ b/core/embed/lib/gl_color.h
@@ -17,13 +17,13 @@
* along with this program. If not, see .
*/
-#ifndef GDC_COLOR_H
-#define GDC_COLOR_H
+#ifndef GL_COLOR_H
+#define GL_COLOR_H
#include
-#define GDC_COLOR_16BIT
-// #define GDC_COLOR_32BIT
+#define GL_COLOR_16BIT
+// #define GL_COLOR_32BIT
// Color in RGB565 format
//
@@ -32,7 +32,7 @@
// |r r r r r g g g | g g g b b b b b|
// |---------------------------------|
-typedef uint16_t gdc_color16_t;
+typedef uint16_t gl_color16_t;
// Color in RGBA8888 format
//
@@ -42,40 +42,40 @@ typedef uint16_t gdc_color16_t;
// |----------------------------------------------------------------------|
//
-typedef uint32_t gdc_color32_t;
-
-#ifdef GDC_COLOR_16BIT
-#define gdc_color_t gdc_color16_t
-#define gdc_color_to_color16(c) (c)
-#define gdc_color16_to_color(c) (c)
-#define gdc_color_to_color32(c) (gdc_color16_to_color32(c))
-#define gdc_color32_to_color(c) (gdc_color32_to_color16(c))
-#define gdc_color_lum(c) (gdc_color16_lum(c))
-#elif GDC_COLOR_32BIT
-#define gdc_color_t gdc_color32_t
-#define gdc_color_to_color16(c) (gdc_color32_to_color16(c))
-#define gdc_color16_to_color(c) (gdc_color16_to_color32(c))
-#define gdc_color_to_color32(c) (c)
-#define gdc_color32_to_color(c) (c)
+typedef uint32_t gl_color32_t;
+
+#ifdef GL_COLOR_16BIT
+#define gl_color_t gl_color16_t
+#define gl_color_to_color16(c) (c)
+#define gl_color16_to_color(c) (c)
+#define gl_color_to_color32(c) (gl_color16_to_color32(c))
+#define gl_color32_to_color(c) (gl_color32_to_color16(c))
+#define gl_color_lum(c) (gl_color16_lum(c))
+#elif GL_COLOR_32BIT
+#define gl_color_t gl_color32_t
+#define gl_color_to_color16(c) (gl_color32_to_color16(c))
+#define gl_color16_to_color(c) (gl_color16_to_color32(c))
+#define gl_color_to_color32(c) (c)
+#define gl_color32_to_color(c) (c)
#else
-#error "GDC_COLOR_16BIT/32BIT not specified"
+#error "GL_COLOR_16BIT/32BIT not specified"
#endif
// Constructs a 16-bit color from the given red (r),
// green (g), and blue (b) values in the range 0..255
-static inline gdc_color16_t gdc_color16_rgb(uint8_t r, uint8_t g, uint8_t b) {
+static inline gl_color16_t gl_color16_rgb(uint8_t r, uint8_t g, uint8_t b) {
return ((r & 0xF8U) << 8) | ((g & 0xFCU) << 3) | ((b & 0xF8U) >> 3);
}
// Constructs a 32-bit color from the given red (r),
// green (g), and blue (b) values in the range 0..255.
// Alpha is set to 255.
-static inline gdc_color32_t gdc_color32_rgb(uint8_t r, uint8_t g, uint8_t b) {
+static inline gl_color32_t gl_color32_rgb(uint8_t r, uint8_t g, uint8_t b) {
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
// Converts a 16-bit color to a 32-bit color; alpha is set to 255
-static inline gdc_color32_t gdc_color16_to_color32(gdc_color16_t color) {
+static inline gl_color32_t gl_color16_to_color32(gl_color16_t color) {
uint32_t r = (color & 0xF800) >> 8;
uint32_t g = (color & 0x07E0) >> 3;
uint32_t b = (color & 0x001F) << 3;
@@ -88,7 +88,7 @@ static inline gdc_color32_t gdc_color16_to_color32(gdc_color16_t color) {
}
// Converts 32-bit color to 16-bit color, alpha is ignored
-static inline gdc_color16_t gdc_color32_to_color16(gdc_color32_t color) {
+static inline gl_color16_t gl_color32_to_color16(gl_color32_t color) {
uint16_t r = (color & 0x00F80000) >> 8;
uint16_t g = (color & 0x0000FC00) >> 5;
uint16_t b = (color & 0x000000F8) >> 3;
@@ -97,7 +97,7 @@ static inline gdc_color16_t gdc_color32_to_color16(gdc_color32_t color) {
}
// Converts 16-bit color into luminance (ranging from 0 to 255)
-static inline uint8_t gdc_color_lum(gdc_color16_t color) {
+static inline uint8_t gl_color_lum(gl_color16_t color) {
uint16_t r = (color & 0x00F80000) >> 8;
uint16_t g = (color & 0x0000FC00) >> 5;
uint16_t b = (color & 0x000000F8) >> 3;
@@ -105,16 +105,15 @@ static inline uint8_t gdc_color_lum(gdc_color16_t color) {
return (r + g + b) / 3;
}
-#ifdef GDC_COLOR_16BIT
+#ifdef GL_COLOR_16BIT
// Blends foreground and background colors with 4-bit alpha
//
// Returns a color in 16-bit format
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
-static inline gdc_color16_t gdc_color16_blend_a4(gdc_color16_t fg,
- gdc_color16_t bg,
- uint8_t alpha) {
+static inline gl_color16_t gl_color16_blend_a4(gl_color16_t fg, gl_color16_t bg,
+ uint8_t alpha) {
uint16_t fg_r = (fg & 0xF800) >> 11;
uint16_t bg_r = (bg & 0xF800) >> 11;
@@ -137,9 +136,8 @@ static inline gdc_color16_t gdc_color16_blend_a4(gdc_color16_t fg,
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
-static inline gdc_color16_t gdc_color16_blend_a8(gdc_color16_t fg,
- gdc_color16_t bg,
- uint8_t alpha) {
+static inline gl_color16_t gl_color16_blend_a8(gl_color16_t fg, gl_color16_t bg,
+ uint8_t alpha) {
uint16_t fg_r = (fg & 0xF800) >> 11;
uint16_t bg_r = (bg & 0xF800) >> 11;
@@ -162,9 +160,8 @@ static inline gdc_color16_t gdc_color16_blend_a8(gdc_color16_t fg,
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
-static inline gdc_color32_t gdc_color32_blend_a4(gdc_color16_t fg,
- gdc_color16_t bg,
- uint8_t alpha) {
+static inline gl_color32_t gl_color32_blend_a4(gl_color16_t fg, gl_color16_t bg,
+ uint8_t alpha) {
uint16_t fg_r = (fg & 0xF800) >> 8;
fg_r |= fg_r >> 5;
uint16_t bg_r = (bg & 0xF800) >> 8;
@@ -187,7 +184,7 @@ static inline gdc_color32_t gdc_color32_blend_a4(gdc_color16_t fg,
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
}
-#elif GDC_COLOR_32BIT
+#elif GL_COLOR_32BIT
// Blends foreground and background colors with 4-bit alpha
//
@@ -195,9 +192,8 @@ static inline gdc_color32_t gdc_color32_blend_a4(gdc_color16_t fg,
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
-static inline gdc_color16_t gdc_color16_blend_a4(gdc_color32_t fg,
- gdc_color32_t bg,
- uint8_t alpha) {
+static inline gl_color16_t gl_color16_blend_a4(gl_color32_t fg, gl_color32_t bg,
+ uint8_t alpha) {
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
uint16_t bg_r = (bg & 0x00FF0000) >> 16;
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
@@ -210,7 +206,7 @@ static inline gdc_color16_t gdc_color16_blend_a4(gdc_color32_t fg,
uint16_t bg_b = (bg & 0x000000FF) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
- return gdc_color16_rgb(r, g, b)
+ return gl_color16_rgb(r, g, b)
}
// Blends foreground and background colors with 8-bit alpha
@@ -219,9 +215,8 @@ static inline gdc_color16_t gdc_color16_blend_a4(gdc_color32_t fg,
//
// If alpha is 0, the function returns the background color
// If alpha is 255, the function returns the foreground color
-static inline gdc_color16_t gdc_color16_blend_a8(gdc_color32_t fg,
- gdc_color32_t bg,
- uint8_t alpha) {
+static inline gl_color16_t gl_color16_blend_a8(gl_color32_t fg, gl_color32_t bg,
+ uint8_t alpha) {
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
uint16_t bg_r = (bg & 0x00FF0000) >> 16;
uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255;
@@ -234,19 +229,17 @@ static inline gdc_color16_t gdc_color16_blend_a8(gdc_color32_t fg,
uint16_t bg_b = (bg & 0x000000FF) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
- return gdc_color16_rgb(r, g, b)
+ return gl_color16_rgb(r, g, b)
}
-
// Blends foreground and background colors with 4-bit alpha
//
// Returns a color in 32-bit format
//
// If alpha is 0, the function returns the background color
// If alpha is 15, the function returns the foreground color
-static inline gdc_color32_t gdc_color32_blend_a4(gdc_color32_t fg,
- gdc_color32_t bg,
- uint8_t alpha) {
+static inline gl_color32_t gl_color32_blend_a4(gl_color32_t fg, gl_color32_t bg,
+ uint8_t alpha) {
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
uint16_t bg_r = (bg & 0x00FF0000) >> 16;
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
@@ -259,23 +252,23 @@ static inline gdc_color32_t gdc_color32_blend_a4(gdc_color32_t fg,
uint16_t bg_b = (bg & 0x000000FF) >> 0;
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
- return gdc_color32_rgb(r, g, b);
+ return gl_color32_rgb(r, g, b);
}
#else
-#error "GDC_COLOR_16BIT/32BIT not specified"
+#error "GL_COLOR_16BIT/32BIT not specified"
#endif
// Returns a gradient as an array of 16 consecutive 16-bit colors
//
// Each element in the array represents a color, with retval[0] being
// the background (bg) color and retval[15] the foreground (fg) color
-const gdc_color16_t* gdc_color16_gradient_a4(gdc_color_t fg, gdc_color_t bg);
+const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg, gl_color_t bg);
// Returns a gradient as an array of 16 consecutive 32-bit colors
//
// Each element in the array represents a color, with retval[0] being
// the background (bg) color and retval[15] the foreground (fg) color
-const gdc_color32_t* gdc_color32_gradient_a4(gdc_color_t fg, gdc_color_t bg);
+const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg, gl_color_t bg);
-#endif // TREZORHAL_GDC_COLOR_H
+#endif // TREZORHAL_GL_COLOR_H
diff --git a/core/embed/gdc/gdc_ops.h b/core/embed/lib/gl_dma2d.h
similarity index 70%
rename from core/embed/gdc/gdc_ops.h
rename to core/embed/lib/gl_dma2d.h
index 7efd32e20..32ecae726 100644
--- a/core/embed/gdc/gdc_ops.h
+++ b/core/embed/lib/gl_dma2d.h
@@ -17,7 +17,36 @@
* along with this program. If not, see .
*/
-#include "gdc_dma2d.h"
+#ifndef GL_DMA2D_H
+#define GL_DMA2D_H
+
+#include
+#include
+
+#include "gl_color.h"
+
+typedef struct {
+ // Destination bitma[
+ // Following fields are used for all operations
+ uint16_t height;
+ uint16_t width;
+ void* dst_row;
+ uint16_t dst_x;
+ uint16_t dst_y;
+ uint16_t dst_stride;
+
+ // Source bitmap
+ // Used for copying and blending, but src_fg & src_alpha
+ // fields are also used for fill operation
+ void* src_row;
+ uint16_t src_x;
+ uint16_t src_y;
+ uint16_t src_stride;
+ gl_color_t src_fg;
+ gl_color_t src_bg;
+ uint8_t src_alpha;
+
+} dma2d_params_t;
bool rgb565_fill(const dma2d_params_t* dp);
bool rgb565_copy_mono4(const dma2d_params_t* dp);
@@ -36,5 +65,4 @@ bool mono8_copy_mono4(const dma2d_params_t* dp);
bool mono8_blend_mono1p(const dma2d_params_t* dp);
bool mono8_blend_mono4(const dma2d_params_t* dp);
-bool wnd565_fill(const dma2d_params_t* dp);
-bool wnd565_copy_rgb565(const dma2d_params_t* dp);
+#endif // GL_DMA2D_H
\ No newline at end of file
diff --git a/core/embed/gdc/gdc_mono8_ops.c b/core/embed/lib/gl_dma2d_mono8.c
similarity index 90%
rename from core/embed/gdc/gdc_mono8_ops.c
rename to core/embed/lib/gl_dma2d_mono8.c
index 86f479aa6..b385d0a57 100644
--- a/core/embed/gdc/gdc_mono8_ops.c
+++ b/core/embed/lib/gl_dma2d_mono8.c
@@ -17,14 +17,13 @@
* along with this program. If not, see .
*/
-#include "gdc_color.h"
-#include "gdc_ops.h"
+#include "gl_dma2d.h"
bool mono8_fill(const dma2d_params_t* dp) {
uint8_t* dst_ptr = (uint8_t*)dp->dst_row + dp->dst_x;
uint16_t height = dp->height;
- uint8_t fg = gdc_color_lum(dp->src_fg);
+ uint8_t fg = gl_color_lum(dp->src_fg);
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
@@ -42,8 +41,8 @@ bool mono8_copy_mono1p(const dma2d_params_t* dp) {
uint16_t src_ofs = dp->src_stride * dp->src_y + dp->src_x;
uint16_t height = dp->height;
- uint8_t fg = gdc_color_lum(dp->src_fg);
- uint8_t bg = gdc_color_lum(dp->src_bg);
+ uint8_t fg = gl_color_lum(dp->src_fg);
+ uint8_t bg = gl_color_lum(dp->src_bg);
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
@@ -63,8 +62,8 @@ bool mono8_copy_mono4(const dma2d_params_t* dp) {
uint8_t* src_row = (uint8_t*)dp->src_row;
uint16_t height = dp->height;
- uint8_t fg = gdc_color_lum(dp->src_fg);
- uint8_t bg = gdc_color_lum(dp->src_bg);
+ uint8_t fg = gl_color_lum(dp->src_fg);
+ uint8_t bg = gl_color_lum(dp->src_bg);
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
@@ -85,7 +84,7 @@ bool mono8_blend_mono1p(const dma2d_params_t* dp) {
uint16_t src_ofs = dp->src_stride * dp->src_y + dp->src_x;
uint16_t height = dp->height;
- uint8_t fg = gdc_color_lum(dp->src_fg);
+ uint8_t fg = gl_color_lum(dp->src_fg);
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
@@ -105,7 +104,7 @@ bool mono8_blend_mono4(const dma2d_params_t* dp) {
uint8_t* src_row = (uint8_t*)dp->src_row;
uint16_t height = dp->height;
- uint8_t fg = gdc_color_lum(dp->src_fg);
+ uint8_t fg = gl_color_lum(dp->src_fg);
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
diff --git a/core/embed/gdc/gdc_rgb565_ops.c b/core/embed/lib/gl_dma2d_rgb565.c
similarity index 91%
rename from core/embed/gdc/gdc_rgb565_ops.c
rename to core/embed/lib/gl_dma2d_rgb565.c
index 48eb3f1e3..b6f4a2d2d 100644
--- a/core/embed/gdc/gdc_rgb565_ops.c
+++ b/core/embed/lib/gl_dma2d_rgb565.c
@@ -17,8 +17,7 @@
* along with this program. If not, see .
*/
-#include "gdc_dma2d.h"
-#include "gdc_ops.h"
+#include "gl_dma2d.h"
#if USE_DMA2D
#include "dma2d.h"
@@ -41,12 +40,11 @@ bool rgb565_fill(const dma2d_params_t* dp) {
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
}
- }
- else {
+ } else {
uint8_t alpha = dp->src_alpha;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
- dst_ptr[x] = gdc_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha);
+ dst_ptr[x] = gl_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
}
@@ -62,8 +60,8 @@ bool rgb565_copy_mono4(const dma2d_params_t* dp) {
} else
#endif
{
- const gdc_color16_t* gradient =
- gdc_color16_gradient_a4(dp->src_fg, dp->src_bg);
+ const gl_color16_t* gradient =
+ gl_color16_gradient_a4(dp->src_fg, dp->src_bg);
uint16_t* dst_ptr = (uint16_t*)dp->dst_row + dp->dst_x;
uint8_t* src_row = (uint8_t*)dp->src_row;
@@ -121,8 +119,8 @@ bool rgb565_blend_mono4(const dma2d_params_t* dp) {
for (int x = 0; x < dp->width; x++) {
uint8_t fg_data = src_row[(x + dp->src_x) / 2];
uint8_t fg_alpha = (x + dp->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
- dst_ptr[x] = gdc_color16_blend_a4(
- dp->src_fg, gdc_color16_to_color(dst_ptr[x]), fg_alpha);
+ dst_ptr[x] = gl_color16_blend_a4(
+ dp->src_fg, gl_color16_to_color(dst_ptr[x]), fg_alpha);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_row += dp->src_stride / sizeof(*src_row);
diff --git a/core/embed/lib/gl_draw.c b/core/embed/lib/gl_draw.c
new file mode 100644
index 000000000..cb6addc09
--- /dev/null
+++ b/core/embed/lib/gl_draw.c
@@ -0,0 +1,226 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include "display_draw.h"
+#include "fonts/fonts.h"
+#include "gl_draw.h"
+
+typedef struct {
+ int16_t dst_x;
+ int16_t dst_y;
+ int16_t src_x;
+ int16_t src_y;
+ int16_t width;
+ int16_t height;
+} gl_clip_t;
+
+static inline gl_clip_t gl_clip(gl_rect_t dst, const gl_bitmap_t* bitmap) {
+ int16_t dst_x = dst.x0;
+ int16_t dst_y = dst.y0;
+
+ int16_t src_x = 0;
+ int16_t src_y = 0;
+
+ if (bitmap != NULL) {
+ src_x += bitmap->offset.x;
+ src_y += bitmap->offset.y;
+
+ // Normalize negative x-offset of bitmap
+ if (src_x < 0) {
+ dst_x -= src_x;
+ src_x = 0;
+ }
+
+ // Normalize negative y-offset of src bitmap
+ if (src_y < 0) {
+ dst_y -= src_y;
+ src_y = 0;
+ }
+ }
+
+ // Normalize negative top-left of destination rectangle
+ if (dst_x < 0) {
+ src_x -= dst_x;
+ dst_x = 0;
+ }
+
+ if (dst_y < 0) {
+ src_y -= dst_y;
+ dst_y = 0;
+ }
+
+ // Calculate dimension of effective rectangle
+ int16_t width = MIN(DISPLAY_RESX, dst.x1) - dst_x;
+ int16_t height = MIN(DISPLAY_RESY, dst.y1) - dst_y;
+
+ if (bitmap != NULL) {
+ width = MIN(width, bitmap->size.x - src_x);
+ height = MIN(height, bitmap->size.y - src_y);
+ }
+
+ gl_clip_t clip = {
+ .dst_x = dst_x,
+ .dst_y = dst_y,
+ .src_x = src_x,
+ .src_y = src_y,
+ .width = width,
+ .height = height,
+ };
+
+ return clip;
+}
+
+void gl_draw_bar(gl_rect_t rect, gl_color_t color) {
+ gl_clip_t clip = gl_clip(rect, NULL);
+
+ if (clip.width <= 0 || clip.height <= 0) {
+ return;
+ }
+
+ dma2d_params_t dp = {
+ // Destination bitmap
+ .height = clip.height,
+ .width = clip.width,
+ .dst_row = NULL,
+ .dst_x = clip.dst_x,
+ .dst_y = clip.dst_y,
+ .dst_stride = 0,
+
+ // Source bitmap
+ .src_fg = color,
+ .src_alpha = 255,
+ };
+
+ display_fill(&dp);
+}
+
+void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap) {
+ gl_clip_t clip = gl_clip(rect, bitmap);
+
+ if (clip.width <= 0 || clip.height <= 0) {
+ return;
+ }
+
+ dma2d_params_t dp = {
+ // Destination bitmap
+ .height = clip.height,
+ .width = clip.width,
+ .dst_row = NULL,
+ .dst_x = clip.dst_x,
+ .dst_y = clip.dst_y,
+ .dst_stride = 0,
+
+ // Source bitmap
+ .src_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.src_y,
+ .src_x = clip.src_x,
+ .src_y = clip.src_y,
+ .src_stride = bitmap->stride,
+ .src_fg = bitmap->fg_color,
+ .src_bg = bitmap->bg_color,
+ .src_alpha = 255,
+ };
+
+#if TREZOR_FONT_BPP == 1
+ if (bitmap->format == GL_FORMAT_MONO1P) {
+ display_copy_mono1p(&dp);
+ }
+#endif
+#if TREZOR_FONT_BPP == 4
+ if (bitmap->format == GL_FORMAT_MONO4) {
+ display_copy_mono4(&dp);
+ }
+#endif
+}
+
+#if TREZOR_FONT_BPP == 1
+#define GLYPH_FORMAT GL_FORMAT_MONO1P
+#define GLYPH_STRIDE(w) (((w) + 7) / 8)
+#elif TREZOR_FONT_BPP == 2
+#error Unsupported TREZOR_FONT_BPP value
+#define GLYPH_FORMAT GL_FORMAT_MONO2
+#define GLYPH_STRIDE(w) (((w) + 3) / 4)
+#elif TREZOR_FONT_BPP == 4
+#define GLYPH_FORMAT GL_FORMAT_MONO4
+#define GLYPH_STRIDE(w) (((w) + 1) / 2)
+#elif TREZOR_FONT_BPP == 8
+#error Unsupported TREZOR_FONT_BPP value
+#define GLYPH_FORMAT GL_FORMAT_MONO8
+#define GLYPH_STRIDE(w) (w)
+#else
+#error Unsupported TREZOR_FONT_BPP value
+#endif
+
+#define GLYPH_WIDTH(g) ((g)[0])
+#define GLYPH_HEIGHT(g) ((g)[1])
+#define GLYPH_ADVANCE(g) ((g)[2])
+#define GLYPH_BEARING_X(g) ((g)[3])
+#define GLYPH_BEARING_Y(g) ((g)[4])
+#define GLYPH_DATA(g) ((void*)&(g)[5])
+
+void gl_draw_text(gl_rect_t rect, const char* text, size_t maxlen,
+ const gl_text_attr_t* attr) {
+ if (text == NULL) {
+ return;
+ }
+
+ gl_bitmap_t bitmap = {
+ .format = GLYPH_FORMAT,
+ .fg_color = attr->fg_color,
+ .bg_color = attr->bg_color,
+ };
+
+ int max_height = font_max_height(attr->font);
+ int baseline = font_baseline(attr->font);
+
+ for (int i = 0; i < maxlen; i++) {
+ uint8_t ch = (uint8_t)text[i];
+
+ if (ch == 0 || rect.x0 >= rect.x1) {
+ break;
+ }
+
+ const uint8_t* glyph = font_get_glyph(attr->font, ch);
+
+ if (glyph == NULL) {
+ continue;
+ }
+
+ bitmap.ptr = GLYPH_DATA(glyph);
+ bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
+ bitmap.size.x = GLYPH_WIDTH(glyph);
+ bitmap.size.y = GLYPH_HEIGHT(glyph);
+
+ bitmap.offset.x = -GLYPH_BEARING_X(glyph);
+ bitmap.offset.y = -(max_height - baseline - GLYPH_BEARING_Y(glyph));
+
+ gl_draw_bitmap(rect, &bitmap);
+
+ rect.x0 += GLYPH_ADVANCE(glyph);
+ }
+}
+
+// ===============================================================
+// emulation of legacy functions
+
+void display_bar(int x, int y, int w, int h, uint16_t c) {}
+
+void display_text(int x, int y, const char* text, int textlen, int font,
+ uint16_t fgcolor, uint16_t bgcolor) {}
diff --git a/core/embed/lib/gl_draw.h b/core/embed/lib/gl_draw.h
new file mode 100644
index 000000000..8c9d36b2d
--- /dev/null
+++ b/core/embed/lib/gl_draw.h
@@ -0,0 +1,135 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef GL_DRAW_H
+#define GL_DRAW_H
+
+#include "gl_color.h"
+
+// 2D rectangle coordinates (x1, y1 point is not included)
+typedef struct {
+ int16_t x0;
+ int16_t y0;
+ int16_t x1;
+ int16_t y1;
+} gl_rect_t;
+
+// Creates a rectangle from top-left coordinates and dimensions
+static inline gl_rect_t gl_rect_wh(int16_t x, int16_t y, int16_t w, int16_t h) {
+ gl_rect_t rect = {
+ .x0 = x,
+ .y0 = y,
+ .x1 = x + w,
+ .y1 = y + h,
+ };
+
+ return rect;
+}
+
+// Creates a rectangle from top-left and bottom-right coordinates
+static inline gl_rect_t gl_rect(int16_t x0, int16_t y0, int16_t x1,
+ int16_t y1) {
+ gl_rect_t rect = {
+ .x0 = x0,
+ .y0 = y0,
+ .x1 = x1,
+ .y1 = y1,
+ };
+
+ return rect;
+}
+
+// 2D offset/ coordinates
+typedef struct {
+ int16_t x;
+ int16_t y;
+} gl_offset_t;
+
+static inline gl_offset_t gl_offset(int16_t x, int16_t y) {
+ gl_offset_t size = {
+ .x = x,
+ .y = y,
+ };
+
+ return size;
+}
+
+// 2D size in pixels
+typedef struct {
+ int16_t x;
+ int16_t y;
+} gl_size_t;
+
+static inline gl_size_t gl_size(int16_t x, int16_t y) {
+ gl_size_t size = {
+ .x = x,
+ .y = y,
+ };
+
+ return size;
+}
+
+// Bitmap pixel format
+typedef enum {
+ GL_FORMAT_UNKNOWN, //
+ GL_FORMAT_MONO1P, // 1-bpp per pixel (packed)
+ GL_FORMAT_MONO4, // 4-bpp per pixel
+ GL_FORMAT_RGB565, // 16-bpp per pixel
+ GL_FORMAT_RGBA8888, // 32-bpp
+} gl_format_t;
+
+// 2D bitmap references
+typedef struct {
+ // pointer to top-left pixel
+ void* ptr;
+ // stride in bytes
+ size_t stride;
+ // size in pixels
+ gl_size_t size;
+ // format of pixels, GL_FORMAT_xxx
+ uint8_t format;
+ // offset used when bitmap is drawed using gl_draw_bitmap()
+ gl_offset_t offset;
+ // foreground color (used with MONOx formats)
+ gl_color_t fg_color;
+ // background color (used with MONOx formats)
+ gl_color_t bg_color;
+} gl_bitmap_t;
+
+// Text attributes
+typedef struct {
+ int font;
+ gl_color_t fg_color;
+ gl_color_t bg_color;
+} gl_text_attr_t;
+
+// Fills a rectangle with a specified color
+void gl_draw_bar(gl_rect_t rect, gl_color_t color);
+
+// Draws a bitmap into the specified rectangle
+// The destination rectangle may not be fully filled if the source bitmap
+// is smaller then destination rectangle or if the bitmap is translated by
+// an offset partially or completely outside the destination rectangle.
+void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap);
+
+// !@# TODO
+void gl_draw_text(gl_rect_t rect, const char* text, size_t maxlen,
+ const gl_text_attr_t* attr);
+
+#endif // GL_DRAW_H
diff --git a/core/embed/lib/terminal.c b/core/embed/lib/terminal.c
index 9411cbdff..1f1625306 100644
--- a/core/embed/lib/terminal.c
+++ b/core/embed/lib/terminal.c
@@ -77,6 +77,9 @@ void term_print(const char *text, int textlen) {
}
}
+#ifdef NEW_RENDERING
+ // TODO !@#
+#else
// render buffer to display
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
@@ -105,6 +108,7 @@ void term_print(const char *text, int textlen) {
}
display_pixeldata_dirty();
display_refresh();
+#endif
}
#ifdef TREZOR_EMULATOR
diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml
index 2381cdfa7..0ae540760 100644
--- a/core/embed/rust/Cargo.toml
+++ b/core/embed/rust/Cargo.toml
@@ -14,6 +14,10 @@ micropython = []
protobuf = ["micropython"]
ui = []
dma2d = []
+xframebuffer = []
+display_mono = []
+display_rgb565 = []
+display_rgba8888 = []
framebuffer = []
framebuffer32bit = []
ui_debug = []
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index 96391af6c..601d2fede 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -110,6 +110,16 @@ fn prepare_bindings() -> bindgen::Builder {
format!("-DTREZOR_BOARD=\"{}\"", board()).as_str(),
]);
+ #[cfg(feature = "xframebuffer")]
+ {
+ bindings = bindings.clang_args(&["-DXFRAMEBUFFER"]);
+ }
+
+ #[cfg(feature = "new_rendering")]
+ {
+ bindings = bindings.clang_args(["-DNEW_RENDERING"]);
+ }
+
// Pass in correct include paths and defines.
if is_firmware() {
let mut clang_args: Vec<&str> = Vec::new();
@@ -338,6 +348,9 @@ fn generate_trezorhal_bindings() {
.allowlist_var("DISPLAY_FRAMEBUFFER_OFFSET_Y")
.allowlist_var("DISPLAY_RESX")
.allowlist_var("DISPLAY_RESY")
+ .allowlist_function("display_get_frame_addr")
+ .allowlist_function("display_fill")
+ .allowlist_function("display_copy_rgb565")
// dma2d
.allowlist_type("dma2d_params_t")
.allowlist_function("rgb565_fill")
@@ -354,8 +367,6 @@ fn generate_trezorhal_bindings() {
.allowlist_function("mono8_copy_mono4")
.allowlist_function("mono8_blend_mono1p")
.allowlist_function("mono8_blend_mono4")
- .allowlist_function("wnd565_fill")
- .allowlist_function("wnd565_copy_rgb565")
// fonts
.allowlist_function("font_height")
.allowlist_function("font_max_height")
diff --git a/core/embed/rust/src/trezorhal/display.rs b/core/embed/rust/src/trezorhal/display.rs
index 95a17350b..593b0572d 100644
--- a/core/embed/rust/src/trezorhal/display.rs
+++ b/core/embed/rust/src/trezorhal/display.rs
@@ -13,11 +13,11 @@ pub use ffi::{
#[cfg(all(feature = "framebuffer", not(feature = "framebuffer32bit")))]
#[derive(Copy, Clone)]
-pub struct FrameBuffer(*mut u16);
+pub struct FrameBuffer(pub *mut u16);
#[cfg(all(feature = "framebuffer", feature = "framebuffer32bit"))]
#[derive(Copy, Clone)]
-pub struct FrameBuffer(*mut u32);
+pub struct FrameBuffer(pub *mut u32);
pub fn backlight(val: i32) -> i32 {
unsafe { ffi::display_backlight(val) }
@@ -99,6 +99,7 @@ pub fn get_fb_addr() -> FrameBuffer {
#[inline(always)]
#[cfg(all(not(feature = "framebuffer"), feature = "disp_i8080_8bit_dw"))]
pub fn pixeldata(c: u16) {
+ #[cfg(not(feature = "new_rendering"))]
unsafe {
ffi::DISPLAY_DATA_ADDRESS.write_volatile((c & 0xff) as u8);
ffi::DISPLAY_DATA_ADDRESS.write_volatile((c >> 8) as u8);
@@ -178,3 +179,8 @@ pub fn clear() {
ffi::display_clear();
}
}
+
+#[cfg(feature = "xframebuffer")]
+pub fn get_frame_addr() -> *mut cty::c_void {
+ unsafe { ffi::display_get_frame_addr() }
+}
diff --git a/core/embed/rust/src/trezorhal/dma2d_new.rs b/core/embed/rust/src/trezorhal/dma2d_new.rs
index 3c4e10f63..d2b39012b 100644
--- a/core/embed/rust/src/trezorhal/dma2d_new.rs
+++ b/core/embed/rust/src/trezorhal/dma2d_new.rs
@@ -142,7 +142,10 @@ impl Dma2d {
}
pub fn wait_for_transfer() {
- unsafe { ffi::dma2d_wait_for_transfer() }
+ #[cfg(feature = "dma2d")]
+ unsafe {
+ ffi::dma2d_wait_for_transfer()
+ }
}
pub unsafe fn rgb565_fill(&self) {
@@ -201,11 +204,13 @@ impl Dma2d {
unsafe { ffi::mono8_blend_mono4(self) };
}
- pub unsafe fn wnd565_fill(&self) {
- unsafe { ffi::wnd565_fill(self) };
+ #[cfg(feature = "new_rendering")]
+ pub unsafe fn display_fill(&self) {
+ unsafe { ffi::display_fill(self) };
}
- pub unsafe fn wnd565_copy_rgb565(&self) {
- unsafe { ffi::wnd565_copy_rgb565(self) };
+ #[cfg(feature = "new_rendering")]
+ pub unsafe fn display_copy_rgb565(&self) {
+ unsafe { ffi::display_copy_rgb565(self) };
}
}
diff --git a/core/embed/rust/src/ui/shape/display/fake_display.rs b/core/embed/rust/src/ui/shape/display/fake_display.rs
new file mode 100644
index 000000000..329a838c9
--- /dev/null
+++ b/core/embed/rust/src/ui/shape/display/fake_display.rs
@@ -0,0 +1,12 @@
+use crate::ui::{
+ display::Color,
+ geometry::Rect,
+ shape::{DirectRenderer, Mono8Canvas},
+};
+
+pub fn render_on_display<'a, F>(_clip: Option, _bg_color: Option, _func: F)
+where
+ F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>),
+{
+ panic!("Not implemented")
+}
diff --git a/core/embed/rust/src/ui/shape/display/fb_mono8.rs b/core/embed/rust/src/ui/shape/display/fb_mono8.rs
new file mode 100644
index 000000000..238fed5c6
--- /dev/null
+++ b/core/embed/rust/src/ui/shape/display/fb_mono8.rs
@@ -0,0 +1,45 @@
+use crate::ui::{
+ display::Color,
+ geometry::{Offset, Rect},
+ shape::{BasicCanvas, DirectRenderer, DrawingCache, Mono8Canvas, Viewport},
+};
+
+use crate::trezorhal::display;
+
+use static_alloc::Bump;
+
+pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F)
+where
+ F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>),
+{
+ static mut BUMP: Bump<[u8; 40 * 1024]> = Bump::uninit();
+
+ let bump = unsafe { &mut *core::ptr::addr_of_mut!(BUMP) };
+ {
+ let width = display::DISPLAY_RESX as i16;
+ let height = display::DISPLAY_RESY as i16;
+
+ bump.reset();
+
+ let cache = DrawingCache::new(bump, bump);
+
+ let fb = unsafe {
+ core::slice::from_raw_parts_mut(
+ display::get_frame_addr() as *mut u8,
+ width as usize * height as usize * core::mem::size_of::(),
+ )
+ };
+
+ let mut canvas = unwrap!(Mono8Canvas::new(Offset::new(width, height), None, fb));
+
+ if let Some(clip) = clip {
+ canvas.set_viewport(Viewport::new(clip));
+ }
+
+ let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
+
+ func(&mut target);
+
+ display::refresh();
+ }
+}
diff --git a/core/embed/rust/src/ui/shape/display/fb_rgb565.rs b/core/embed/rust/src/ui/shape/display/fb_rgb565.rs
new file mode 100644
index 000000000..986a10d75
--- /dev/null
+++ b/core/embed/rust/src/ui/shape/display/fb_rgb565.rs
@@ -0,0 +1,51 @@
+use crate::ui::{
+ display::Color,
+ geometry::{Offset, Rect},
+ shape::{BasicCanvas, DirectRenderer, DrawingCache, Rgb565Canvas, Viewport},
+};
+
+use crate::trezorhal::display;
+
+use static_alloc::Bump;
+
+pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F)
+where
+ F: FnOnce(&mut DirectRenderer<'_, 'a, Rgb565Canvas<'a>>),
+{
+ #[link_section = ".no_dma_buffers"]
+ static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit();
+
+ #[link_section = ".buf"]
+ static mut BUMP_B: Bump<[u8; 16 * 1024]> = Bump::uninit();
+
+ let bump_a = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_A) };
+ let bump_b = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_B) };
+ {
+ let width = display::DISPLAY_RESX as i16;
+ let height = display::DISPLAY_RESY as i16;
+
+ bump_a.reset();
+ bump_b.reset();
+
+ let cache = DrawingCache::new(bump_a, bump_b);
+
+ let fb = unsafe {
+ core::slice::from_raw_parts_mut(
+ display::get_frame_addr() as *mut u8,
+ width as usize * height as usize * core::mem::size_of::(),
+ )
+ };
+
+ let mut canvas = unwrap!(Rgb565Canvas::new(Offset::new(width, height), None, fb));
+
+ if let Some(clip) = clip {
+ canvas.set_viewport(Viewport::new(clip));
+ }
+
+ let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
+
+ func(&mut target);
+
+ display::refresh();
+ }
+}
diff --git a/core/embed/rust/src/ui/shape/display/fb_rgba8888.rs b/core/embed/rust/src/ui/shape/display/fb_rgba8888.rs
new file mode 100644
index 000000000..f731b403c
--- /dev/null
+++ b/core/embed/rust/src/ui/shape/display/fb_rgba8888.rs
@@ -0,0 +1,51 @@
+use crate::ui::{
+ display::Color,
+ geometry::{Offset, Rect},
+ shape::{BasicCanvas, DirectRenderer, DrawingCache, Rgba8888Canvas, Viewport},
+};
+
+use static_alloc::Bump;
+
+use crate::trezorhal::display;
+
+pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F)
+where
+ F: FnOnce(&mut DirectRenderer<'_, 'a, Rgba8888Canvas<'a>>),
+{
+ #[link_section = ".no_dma_buffers"]
+ static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit();
+
+ #[link_section = ".buf"]
+ static mut BUMP_B: Bump<[u8; 16 * 1024]> = Bump::uninit();
+
+ let bump_a = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_A) };
+ let bump_b = unsafe { &mut *core::ptr::addr_of_mut!(BUMP_B) };
+ {
+ let width = display::DISPLAY_RESX as i16;
+ let height = display::DISPLAY_RESY as i16;
+
+ bump_a.reset();
+ bump_b.reset();
+
+ let cache = DrawingCache::new(bump_a, bump_b);
+
+ let fb = unsafe {
+ core::slice::from_raw_parts_mut(
+ display::get_frame_addr() as *mut u8,
+ width as usize * height as usize * core::mem::size_of::(),
+ )
+ };
+
+ let mut canvas = unwrap!(Rgba8888Canvas::new(Offset::new(width, height), None, fb));
+
+ if let Some(clip) = clip {
+ canvas.set_viewport(Viewport::new(clip));
+ }
+
+ let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
+
+ func(&mut target);
+
+ display::refresh();
+ }
+}
diff --git a/core/embed/rust/src/ui/shape/model/memory.md b/core/embed/rust/src/ui/shape/display/memory.md
similarity index 100%
rename from core/embed/rust/src/ui/shape/model/memory.md
rename to core/embed/rust/src/ui/shape/display/memory.md
diff --git a/core/embed/rust/src/ui/shape/display/mod.rs b/core/embed/rust/src/ui/shape/display/mod.rs
new file mode 100644
index 000000000..c2f094d53
--- /dev/null
+++ b/core/embed/rust/src/ui/shape/display/mod.rs
@@ -0,0 +1,24 @@
+#[cfg(all(feature = "xframebuffer", feature = "display_mono"))]
+pub mod fb_mono8;
+#[cfg(all(feature = "xframebuffer", feature = "display_mono"))]
+pub use fb_mono8::render_on_display;
+
+#[cfg(all(not(feature = "xframebuffer"), feature = "display_rgb565"))]
+pub mod nofb_rgb565;
+#[cfg(all(not(feature = "xframebuffer"), feature = "display_rgb565"))]
+pub use nofb_rgb565::render_on_display;
+
+#[cfg(all(feature = "xframebuffer", feature = "display_rgb565"))]
+pub mod fb_rgb565;
+#[cfg(all(feature = "xframebuffer", feature = "display_rgb565"))]
+pub use fb_rgb565::render_on_display;
+
+#[cfg(all(feature = "xframebuffer", feature = "display_rgba8888"))]
+pub mod fb_rgba8888;
+#[cfg(all(feature = "xframebuffer", feature = "display_rgba8888"))]
+pub use fb_rgba8888::render_on_display;
+
+#[cfg(not(feature = "new_rendering"))]
+pub mod fake_display;
+#[cfg(not(feature = "new_rendering"))]
+pub use fake_display::render_on_display;
diff --git a/core/embed/rust/src/ui/shape/model/model_tt.rs b/core/embed/rust/src/ui/shape/display/nofb_rgb565.rs
similarity index 88%
rename from core/embed/rust/src/ui/shape/model/model_tt.rs
rename to core/embed/rust/src/ui/shape/display/nofb_rgb565.rs
index e92bd35af..b1ce7a947 100644
--- a/core/embed/rust/src/ui/shape/model/model_tt.rs
+++ b/core/embed/rust/src/ui/shape/display/nofb_rgb565.rs
@@ -13,7 +13,7 @@ use static_alloc::Bump;
pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F)
where
- F: FnOnce(&mut ProgressiveRenderer<'_, 'a, Bump<[u8; 40 * 1024]>, DisplayModelT>),
+ F: FnOnce(&mut ProgressiveRenderer<'_, 'a, Bump<[u8; 40 * 1024]>, DisplayCanvas>),
{
#[link_section = ".no_dma_buffers"]
static mut BUMP_A: Bump<[u8; 40 * 1024]> = Bump::uninit();
@@ -28,7 +28,7 @@ where
bump_b.reset();
let cache = DrawingCache::new(bump_a, bump_b);
- let mut canvas = DisplayModelT::acquire().unwrap();
+ let mut canvas = DisplayCanvas::acquire().unwrap();
if let Some(clip) = clip {
canvas.set_viewport(Viewport::new(clip));
@@ -42,12 +42,12 @@ where
}
}
-pub struct DisplayModelT {
+pub struct DisplayCanvas {
size: Offset,
viewport: Viewport,
}
-impl DisplayModelT {
+impl DisplayCanvas {
pub fn acquire() -> Option {
let size = Offset::new(240, 240); // TODO
let viewport = Viewport::from_size(size);
@@ -55,7 +55,7 @@ impl DisplayModelT {
}
}
-impl BasicCanvas for DisplayModelT {
+impl BasicCanvas for DisplayCanvas {
fn viewport(&self) -> Viewport {
self.viewport
}
@@ -71,7 +71,7 @@ impl BasicCanvas for DisplayModelT {
fn fill_rect(&mut self, r: Rect, color: Color, _alpha: u8) {
let r = r.translate(self.viewport.origin);
if let Some(dma2d) = Dma2d::new_fill(r, self.viewport.clip, color, 255) {
- unsafe { dma2d.wnd565_fill() };
+ unsafe { dma2d.display_fill() };
}
}
@@ -79,7 +79,7 @@ impl BasicCanvas for DisplayModelT {
let r = r.translate(self.viewport.origin);
if let Some(dma2d) = Dma2d::new_copy(r, self.viewport.clip, &bitmap) {
match bitmap.format() {
- BitmapFormat::RGB565 => unsafe { dma2d.wnd565_copy_rgb565() },
+ BitmapFormat::RGB565 => unsafe { dma2d.display_copy_rgb565() },
_ => panic!("Unsupported DMA operation"),
}
bitmap.bitmap.mark_dma_pending();
diff --git a/core/embed/rust/src/ui/shape/mod.rs b/core/embed/rust/src/ui/shape/mod.rs
index dbfe6a1ac..9fc9d7fe2 100644
--- a/core/embed/rust/src/ui/shape/mod.rs
+++ b/core/embed/rust/src/ui/shape/mod.rs
@@ -7,9 +7,9 @@ mod blur;
mod cache;
mod canvas;
mod circle;
+mod display;
#[cfg(feature = "ui_jpeg_decoder")]
mod jpeg;
-mod model;
mod qrcode;
mod render;
mod text;
@@ -24,9 +24,9 @@ pub use blur::Blurring;
pub use cache::drawing_cache::DrawingCache;
pub use canvas::{BasicCanvas, Canvas, Mono8Canvas, Rgb565Canvas, Rgba8888Canvas, Viewport};
pub use circle::Circle;
+pub use display::render_on_display;
#[cfg(feature = "ui_jpeg_decoder")]
pub use jpeg::JpegImage;
-pub use model::render_on_display;
pub use qrcode::QrImage;
pub use render::{DirectRenderer, ProgressiveRenderer, Renderer};
pub use text::Text;
diff --git a/core/embed/rust/src/ui/shape/model/mod.rs b/core/embed/rust/src/ui/shape/model/mod.rs
deleted file mode 100644
index 7a041b13d..000000000
--- a/core/embed/rust/src/ui/shape/model/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#[cfg(feature = "model_tr")]
-pub mod model_tr;
-#[cfg(feature = "model_tr")]
-pub use model_tr::render_on_display;
-
-#[cfg(feature = "model_tt")]
-pub mod model_tt;
-#[cfg(feature = "model_tt")]
-pub use model_tt::render_on_display;
diff --git a/core/embed/rust/src/ui/shape/model/model_tr.rs b/core/embed/rust/src/ui/shape/model/model_tr.rs
deleted file mode 100644
index 3da0bd95d..000000000
--- a/core/embed/rust/src/ui/shape/model/model_tr.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use crate::ui::{
- display,
- display::Color,
- geometry::{Offset, Rect},
- shape::{BasicCanvas, Canvas, DirectRenderer, DrawingCache, Mono8Canvas, Viewport},
-};
-
-use static_alloc::Bump;
-
-pub fn render_on_display<'a, F>(clip: Option, bg_color: Option, func: F)
-where
- F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>),
-{
- // TODO: do not use constants 128 & 64 directly
-
- static mut FRAME_BUFFER: [u8; 128 * 64] = [0u8; 128 * 64];
-
- let fb = &mut unsafe { &mut *core::ptr::addr_of_mut!(FRAME_BUFFER) }[..];
-
- static mut BUMP: Bump<[u8; 40 * 1024]> = Bump::uninit();
-
- let bump = unsafe { &mut *core::ptr::addr_of_mut!(BUMP) };
- {
- bump.reset();
-
- let cache = DrawingCache::new(bump, bump);
- let mut canvas = unwrap!(Mono8Canvas::new(Offset::new(128, 64), None, fb));
-
- if let Some(clip) = clip {
- canvas.set_viewport(Viewport::new(clip));
- }
-
- let mut target = DirectRenderer::new(&mut canvas, bg_color, &cache);
-
- func(&mut target);
-
- refresh_display(&canvas);
- }
-}
-
-fn refresh_display(canvas: &Mono8Canvas) {
- // TODO: optimize
-
- display::set_window(canvas.bounds());
-
- let view = canvas.view();
-
- for y in 0..canvas.size().y {
- let row = unwrap!(view.row(y));
- for value in row.iter() {
- let c = Color::rgb(*value, *value, *value);
- display::pixeldata(c.into());
- }
- }
-
- display::refresh();
-}
diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h
index 5e9ee471b..e4daafef9 100644
--- a/core/embed/rust/trezorhal.h
+++ b/core/embed/rust/trezorhal.h
@@ -1,13 +1,14 @@
#include TREZOR_BOARD
-#include "../gdc/gdc.h"
#include "buffers.h"
#include "button.h"
#include "common.h"
#include "display.h"
+#include "display_draw.h"
#include "dma2d.h"
#include "flash.h"
#include "fonts/fonts.h"
+#include "gl_dma2d.h"
#include "haptic.h"
#include "model.h"
#include "rgb_led.h"
diff --git a/core/embed/trezorhal/boards/stm32f429i-disc1.h b/core/embed/trezorhal/boards/stm32f429i-disc1.h
index 9f8b0a65e..cd37a9712 100644
--- a/core/embed/trezorhal/boards/stm32f429i-disc1.h
+++ b/core/embed/trezorhal/boards/stm32f429i-disc1.h
@@ -3,18 +3,16 @@
#define HSE_8MHZ
-#define MAX_DISPLAY_RESX 240
-#define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240
#define DISPLAY_RESY 320
+#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
+#define DISPLAY_LEGACY_HEADER "displays/ltdc.h"
#define USE_I2C 1
#define USE_TOUCH 1
#define USE_SDRAM 1
#define USE_RGB_COLORS 1
-#include "displays/ltdc.h"
-
#define I2C_COUNT 1
#define I2C_INSTANCE_0 I2C3
#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C3_CLK_ENABLE
diff --git a/core/embed/trezorhal/boards/stm32u5a9j-dk.h b/core/embed/trezorhal/boards/stm32u5a9j-dk.h
index 3ff3673ee..5b1ab241a 100644
--- a/core/embed/trezorhal/boards/stm32u5a9j-dk.h
+++ b/core/embed/trezorhal/boards/stm32u5a9j-dk.h
@@ -11,7 +11,10 @@
//#define USE_DISP_I8080_8BIT_DW 1
#define USE_HASH_PROCESSOR 1
-#include "displays/dsi.h"
+#define DISPLAY_RESX 480
+#define DISPLAY_RESY 480
+#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888
+#define DISPLAY_LEGACY_HEADER "displays/dsi.h"
#define I2C_COUNT 1
#define I2C_INSTANCE_0 I2C5
diff --git a/core/embed/trezorhal/boards/trezor_1.h b/core/embed/trezorhal/boards/trezor_1.h
index 4f126a720..7fec05ac7 100644
--- a/core/embed/trezorhal/boards/trezor_1.h
+++ b/core/embed/trezorhal/boards/trezor_1.h
@@ -5,7 +5,8 @@
#define USE_BUTTON 1
-#include "displays/vg-2864ksweg01.h"
+#define DISPLAY_RESX 128
+#define DISPLAY_RESY 64
#define BTN_LEFT_PIN GPIO_PIN_5
#define BTN_LEFT_PORT GPIOC
diff --git a/core/embed/trezorhal/boards/trezor_r_v10.h b/core/embed/trezorhal/boards/trezor_r_v10.h
index be44e5585..b48479d52 100644
--- a/core/embed/trezorhal/boards/trezor_r_v10.h
+++ b/core/embed/trezorhal/boards/trezor_r_v10.h
@@ -8,7 +8,9 @@
#define USE_I2C 1
#define USE_CONSUMPTION_MASK 1
-#include "displays/vg-2864ksweg01.h"
+#define DISPLAY_RESX 128
+#define DISPLAY_RESY 64
+#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h"
#define BTN_LEFT_PIN GPIO_PIN_10
#define BTN_LEFT_PORT GPIOC
diff --git a/core/embed/trezorhal/boards/trezor_r_v3.h b/core/embed/trezorhal/boards/trezor_r_v3.h
index 242a3f541..ffe8b6914 100644
--- a/core/embed/trezorhal/boards/trezor_r_v3.h
+++ b/core/embed/trezorhal/boards/trezor_r_v3.h
@@ -6,7 +6,9 @@
#define USE_BUTTON 1
#define USE_SBU 1
-#include "displays/ug-2828tswig01.h"
+#define DISPLAY_RESX 128
+#define DISPLAY_RESY 128
+#define DISPLAY_LEGACY_HEADER "displays/ug-2828tswig01.h"
#define BTN_LEFT_PIN GPIO_PIN_0
#define BTN_LEFT_PORT GPIOA
diff --git a/core/embed/trezorhal/boards/trezor_r_v4.h b/core/embed/trezorhal/boards/trezor_r_v4.h
index 29054d200..9dbbb6267 100644
--- a/core/embed/trezorhal/boards/trezor_r_v4.h
+++ b/core/embed/trezorhal/boards/trezor_r_v4.h
@@ -6,7 +6,9 @@
#define USE_BUTTON 1
#define USE_SBU 1
-#include "displays/vg-2864ksweg01.h"
+#define DISPLAY_RESX 128
+#define DISPLAY_RESY 64
+#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h"
#define BTN_LEFT_PIN GPIO_PIN_5
#define BTN_LEFT_PORT GPIOC
diff --git a/core/embed/trezorhal/boards/trezor_r_v6.h b/core/embed/trezorhal/boards/trezor_r_v6.h
index 72a7cedea..d177c3d72 100644
--- a/core/embed/trezorhal/boards/trezor_r_v6.h
+++ b/core/embed/trezorhal/boards/trezor_r_v6.h
@@ -6,7 +6,9 @@
#define USE_BUTTON 1
#define USE_SBU 1
-#include "displays/vg-2864ksweg01.h"
+#define DISPLAY_RESX 128
+#define DISPLAY_RESY 64
+#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h"
#define BTN_LEFT_PIN GPIO_PIN_10
#define BTN_LEFT_PORT GPIOC
diff --git a/core/embed/trezorhal/boards/trezor_t.h b/core/embed/trezorhal/boards/trezor_t.h
index 557f8bb55..14e2ffd3f 100644
--- a/core/embed/trezorhal/boards/trezor_t.h
+++ b/core/embed/trezorhal/boards/trezor_t.h
@@ -3,9 +3,6 @@
#define HSE_8MHZ
-#define DISPLAY_RESX 240
-#define DISPLAY_RESY 240
-
#define USE_SD_CARD 1
#define USE_I2C 1
#define USE_TOUCH 1
@@ -14,12 +11,14 @@
#define USE_BACKLIGHT 1
#define USE_DISP_I8080_8BIT_DW 1
-#include "displays/panels/lx154a2422.h"
-#include "displays/st7789v.h"
+#define DISPLAY_RESX 240
+#define DISPLAY_RESY 240
+#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
+#define DISPLAY_LEGACY_HEADER "displays/st7789v.h"
+
#define DISPLAY_IDENTIFY 1
#define DISPLAY_TE_PORT GPIOD
#define DISPLAY_TE_PIN GPIO_PIN_12
-#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords
#define BACKLIGHT_PWM_FREQ 10000
#define BACKLIGHT_PWM_TIM TIM1
diff --git a/core/embed/trezorhal/boards/trezor_t3t1_revE.h b/core/embed/trezorhal/boards/trezor_t3t1_revE.h
index 4724aae75..3f9491bd9 100644
--- a/core/embed/trezorhal/boards/trezor_t3t1_revE.h
+++ b/core/embed/trezorhal/boards/trezor_t3t1_revE.h
@@ -1,9 +1,6 @@
#ifndef _TREZOR_T3T1_H
#define _TREZOR_T3T1_H
-#define DISPLAY_RESX 240
-#define DISPLAY_RESY 240
-
#define VDD_1V8 1
#define HSE_16MHZ 1
@@ -17,8 +14,11 @@
#define USE_BACKLIGHT 1
#define USE_HASH_PROCESSOR 1
-#include "displays/panels/lx154a2422.h"
-#include "displays/st7789v.h"
+#define DISPLAY_RESX 240
+#define DISPLAY_RESY 240
+#define DISPLAY_LEGACY_HEADER "displays/st7789v.h"
+#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
+
#define DISPLAY_IDENTIFY 1
#define DISPLAY_TE_PORT GPIOD
#define DISPLAY_TE_PIN GPIO_PIN_12
@@ -27,10 +27,6 @@
#define DISPLAY_TE_INTERRUPT_GPIOSEL EXTI_GPIOD
#define DISPLAY_TE_INTERRUPT_EXTI_LINE EXTI_LINE_12
-#define DISPLAY_PANEL_INIT_SEQ lx154a2422_init_seq
-#define DISPLAY_PANEL_ROTATE lx154a2422_rotate
-#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords
-
#define BACKLIGHT_PWM_FREQ 12500
#define BACKLIGHT_PWM_TIM TIM17
#define BACKLIGHT_PWM_TIM_CLK_EN __HAL_RCC_TIM17_CLK_ENABLE
diff --git a/core/embed/trezorhal/boards/trezor_t3t1_v4.h b/core/embed/trezorhal/boards/trezor_t3t1_v4.h
index fa5807b00..267dbabd4 100644
--- a/core/embed/trezorhal/boards/trezor_t3t1_v4.h
+++ b/core/embed/trezorhal/boards/trezor_t3t1_v4.h
@@ -1,9 +1,6 @@
#ifndef _TREZOR_T3T1_H
#define _TREZOR_T3T1_H
-#define DISPLAY_RESX 240
-#define DISPLAY_RESY 240
-
#define VDD_1V8 1
#define HSE_16MHZ 1
@@ -17,8 +14,11 @@
#define USE_BACKLIGHT 1
#define USE_HASH_PROCESSOR 1
-#include "displays/panels/lx154a2422.h"
-#include "displays/st7789v.h"
+#define DISPLAY_RESX 240
+#define DISPLAY_RESY 240
+#define DISPLAY_LEGACY_HEADER "displays/st7789v.h"
+#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
+
#define DISPLAY_IDENTIFY 1
#define DISPLAY_TE_PORT GPIOD
#define DISPLAY_TE_PIN GPIO_PIN_12
@@ -27,10 +27,6 @@
#define DISPLAY_TE_INTERRUPT_GPIOSEL EXTI_GPIOD
#define DISPLAY_TE_INTERRUPT_EXTI_LINE EXTI_LINE_12
-#define DISPLAY_PANEL_INIT_SEQ lx154a2422_init_seq
-#define DISPLAY_PANEL_ROTATE lx154a2422_rotate
-#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords
-
#define BACKLIGHT_PWM_FREQ 12500
#define BACKLIGHT_PWM_TIM TIM8
#define BACKLIGHT_PWM_TIM_CLK_EN __HAL_RCC_TIM8_CLK_ENABLE
diff --git a/core/embed/trezorhal/display.h b/core/embed/trezorhal/display.h
index 4cc2a2bc1..1b3f72b0f 100644
--- a/core/embed/trezorhal/display.h
+++ b/core/embed/trezorhal/display.h
@@ -20,11 +20,19 @@
#ifndef TREZORHAL_DISPLAY_H
#define TREZORHAL_DISPLAY_H
+#if NEW_RENDERING
+#include
+#else
+
#include
#include "common.h"
#include "display_draw.h"
#include TREZOR_BOARD
+#ifdef DISPLAY_LEGACY_HEADER
+#include DISPLAY_LEGACY_HEADER
+#endif
+
#ifndef DISPLAY_FRAMEBUFFER_OFFSET_Y
#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0
#endif
@@ -69,4 +77,5 @@ uint8_t *display_get_wr_addr(void);
void display_shift_window(uint16_t pixels);
uint16_t display_get_window_offset(void);
+#endif // NEW_RENDERING
#endif // TREZORHAL_DISPLAY_H
diff --git a/core/embed/trezorhal/dma2d.h b/core/embed/trezorhal/dma2d.h
index 20019cf4e..b389a9ff0 100644
--- a/core/embed/trezorhal/dma2d.h
+++ b/core/embed/trezorhal/dma2d.h
@@ -20,10 +20,12 @@
#ifndef TREZORHAL_DMA2D_H
#define TREZORHAL_DMA2D_H
-#include "../gdc/gdc_core.h"
-
+#include
+#include
#include "common.h"
+#include "gl_dma2d.h"
+
void dma2d_init(void);
void dma2d_setup_const(void);
diff --git a/core/embed/trezorhal/stm32f4/common.c b/core/embed/trezorhal/stm32f4/common.c
index 23f9b8202..62e08db27 100644
--- a/core/embed/trezorhal/stm32f4/common.c
+++ b/core/embed/trezorhal/stm32f4/common.c
@@ -224,7 +224,11 @@ void collect_hw_entropy(void) {
void ensure_compatible_settings(void) {
display_finish_actions();
#ifdef TREZOR_MODEL_T
+#ifdef NEW_RENDERING
+ display_set_compatible_settings();
+#else
display_set_big_endian();
+#endif
display_orientation(0);
set_core_clock(CLOCK_168_MHZ);
backlight_pwm_set_slow();
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_driver.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_driver.c
new file mode 100644
index 000000000..e8f0007cc
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_driver.c
@@ -0,0 +1,194 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include
+
+#include "display_fb.h"
+#include "display_io.h"
+#include "display_panel.h"
+
+#include "backlight_pwm.h"
+
+#include "supervise.h"
+
+#ifndef BOARDLOADER
+#include "bg_copy.h"
+#endif
+
+#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240)
+#error "Incompatible display resolution"
+#endif
+
+// Display driver context.
+typedef struct {
+ // Current display orientation (0, 90, 180, 270)
+ int orientation_angle;
+} display_driver_t;
+
+// Display driver instance
+static display_driver_t g_display_driver;
+
+void display_init(void) {
+ display_driver_t* drv = &g_display_driver;
+ memset(drv, 0, sizeof(display_driver_t));
+
+ display_io_init_gpio();
+ display_io_init_fmc();
+ display_panel_init();
+ display_panel_set_little_endian();
+ backlight_pwm_init();
+
+#ifdef XFRAMEBUFFER
+ display_io_init_te_interrupt();
+#endif
+}
+
+void display_reinit(void) {
+ display_driver_t* drv = &g_display_driver;
+ memset(drv, 0, sizeof(display_driver_t));
+
+ // Reinitialize FMC to set correct timing
+ // We have to do this in reinit because boardloader is fixed.
+ display_io_init_fmc();
+
+ // Important for model T as this is not set in boardloader
+ display_panel_set_little_endian();
+ display_panel_init_gamma();
+ backlight_pwm_reinit();
+
+#ifdef XFRAMEBUFFER
+ display_io_init_te_interrupt();
+#endif
+}
+
+void display_finish_actions(void) {
+ // !@# disable interrupt
+ // !@# wait for dma ops
+}
+
+int display_set_backlight(int level) {
+#ifdef XFRAMEBUFFER
+#ifndef BOARDLOADER
+ // wait for DMA transfer to finish before changing backlight
+ // so that we know that panel has current data
+ if (backlight_pwm_get() != level && !is_mode_handler()) {
+ bg_copy_wait();
+ }
+#endif
+#endif
+
+ return backlight_pwm_set(level);
+}
+
+int display_get_backlight(void) { return backlight_pwm_get(); }
+
+int display_set_orientation(int angle) {
+ display_driver_t* drv = &g_display_driver;
+
+ if (angle != drv->orientation_angle) {
+ if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
+ drv->orientation_angle = angle;
+
+#ifdef XFRAMEBUFFER
+ memset(physical_frame_buffer_0, 0, sizeof(physical_frame_buffer_0));
+ memset(physical_frame_buffer_1, 0, sizeof(physical_frame_buffer_1));
+#endif
+
+ display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
+ for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
+ // 2 bytes per pixel because we're using RGB 5-6-5 format
+ ISSUE_PIXEL_DATA(0x0000);
+ }
+
+ display_panel_rotate(angle);
+ }
+ }
+
+ return drv->orientation_angle;
+}
+
+int display_get_orientation(void) {
+ display_driver_t* drv = &g_display_driver;
+
+ return drv->orientation_angle;
+}
+
+#ifndef XFRAMEBUFFER
+void display_refresh(void) {
+ // if the framebuffer is not used the implementation is empty
+}
+#endif
+
+void display_wait_for_sync(void) {
+#ifdef DISPLAY_TE_PIN
+ uint32_t id = display_panel_identify();
+ if (id && (id != DISPLAY_ID_GC9307)) {
+ // synchronize with the panel synchronization signal
+ // in order to avoid visual tearing effects
+ while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN))
+ ;
+ while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN))
+ ;
+ }
+#endif
+}
+
+const char* display_save(const char* prefix) { return NULL; }
+
+void display_clear_save(void) {}
+
+void display_set_compatible_settings(void) { display_panel_set_big_endian(); }
+
+static inline void set_window(const dma2d_params_t* dp) {
+ display_panel_set_window(dp->dst_x, dp->dst_y, dp->dst_x + dp->width - 1,
+ dp->dst_y + dp->height + 1);
+}
+
+// Fills a rectangle with a specified color
+void display_fill(const dma2d_params_t* dp) {
+ set_window(dp);
+
+ uint16_t height = dp->height;
+
+ while (height-- > 0) {
+ for (int x = 0; x < dp->width; x++) {
+ ISSUE_PIXEL_DATA(dp->src_fg);
+ }
+ }
+}
+
+// Copies an RGB565 bitmap to specified rectangle
+void display_copy_rgb565(const dma2d_params_t* dp) {
+ set_window(dp);
+
+ uint16_t* src_ptr = (uint16_t*)dp->src_row + dp->src_x;
+ uint16_t height = dp->height;
+
+ while (height-- > 0) {
+ for (int x = 0; x < dp->width; x++) {
+ ISSUE_PIXEL_DATA(src_ptr[x]);
+ }
+ src_ptr += dp->src_stride / sizeof(*src_ptr);
+ }
+}
+
+// Copies a MONO4 bitmap to specified rectangle
+// void display_copy_mono4(gdc_dma2d_t *dp);
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.c
new file mode 100644
index 000000000..1e701b0fe
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.c
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "display_fb.h"
+#include "display_io.h"
+#include "display_panel.h"
+
+#include "irq.h"
+#include "supervise.h"
+
+#ifndef BOARDLOADER
+#include "bg_copy.h"
+#endif
+
+#ifdef XFRAMEBUFFER
+
+#ifndef STM32U5
+#error Framebuffer only supported on STM32U5 for now
+#endif
+
+// Physical frame buffers in internal SRAM memory
+__attribute__((section(".fb1")))
+ALIGN_32BYTES(uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
+
+__attribute__((section(".fb2")))
+ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
+
+// The current frame buffer selector at fixed memory address
+// It's shared between bootloaders and the firmware
+__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
+ 0;
+
+static bool pending_fb_switch = false;
+
+#ifndef BOARDLOADER
+void DISPLAY_TE_INTERRUPT_HANDLER(void) {
+ HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM);
+
+ if (current_frame_buffer == 1) {
+ bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_1,
+ (uint8_t *)DISPLAY_DATA_ADDRESS,
+ DISPLAY_RESX * DISPLAY_RESY * 2);
+
+ } else {
+ bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_0,
+ (uint8_t *)DISPLAY_DATA_ADDRESS,
+ DISPLAY_RESX * DISPLAY_RESY * 2);
+ }
+
+ pending_fb_switch = false;
+ __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
+}
+
+static void wait_for_fb_switch(void) {
+ while (pending_fb_switch) {
+ __WFI();
+ }
+ bg_copy_wait();
+}
+#endif
+
+static void copy_fb_to_display(uint16_t *fb) {
+ for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
+ // 2 bytes per pixel because we're using RGB 5-6-5 format
+ ISSUE_PIXEL_DATA(fb[i]);
+ }
+}
+
+static void switch_fb_manually(void) {
+ // sync with the panel refresh
+ while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
+ }
+ while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
+ }
+
+ if (current_frame_buffer == 0) {
+ current_frame_buffer = 1;
+ copy_fb_to_display((uint16_t *)physical_frame_buffer_1);
+ memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
+ sizeof(physical_frame_buffer_0));
+
+ } else {
+ current_frame_buffer = 0;
+ copy_fb_to_display((uint16_t *)physical_frame_buffer_0);
+ memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
+ sizeof(physical_frame_buffer_1));
+ }
+}
+
+#ifndef BOARDLOADER
+static void switch_fb_in_backround(void) {
+ if (current_frame_buffer == 0) {
+ current_frame_buffer = 1;
+
+ memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
+ sizeof(physical_frame_buffer_0));
+
+ pending_fb_switch = true;
+ __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
+ svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM);
+ } else {
+ current_frame_buffer = 0;
+ memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
+ sizeof(physical_frame_buffer_1));
+
+ pending_fb_switch = true;
+ __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
+ svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM);
+ }
+}
+#endif
+
+void *display_get_frame_addr(void) {
+ if (current_frame_buffer == 0) {
+ return (void *)physical_frame_buffer_1;
+ } else {
+ return (void *)physical_frame_buffer_0;
+ }
+}
+
+void display_refresh(void) {
+#ifndef BOARDLOADER
+ wait_for_fb_switch();
+ display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
+
+ if (is_mode_handler()) {
+ switch_fb_manually();
+ } else {
+ switch_fb_in_backround();
+ }
+#else
+ display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
+ switch_fb_manually();
+#endif
+}
+
+#endif // XFRAMEBUFFER
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.h b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.h
new file mode 100644
index 000000000..bad36e107
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_fb.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
+#define TREZOR_HAL_DISPLAY_INTERNAL_H
+
+#include TREZOR_BOARD
+
+#include
+
+#ifdef XFRAMEBUFFER
+
+// Size of the physical frame buffer in bytes
+#define PHYSICAL_FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2)
+
+// Physical frame buffers in internal SRAM memory
+//
+// Both frame buffers layes in the fixed addresses that
+// are shared between bootloaders and the firmware.
+extern uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
+extern uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
+
+// The current frame buffer selector at fixed memory address
+//
+// The variable address is shared between bootloaders and the firmware
+extern uint32_t current_frame_buffer;
+
+#endif // XFRAMEBUFFER
+
+#endif // TREZOR_HAL_DISPLAY_INTERNAL_H
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_io.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.c
new file mode 100644
index 000000000..fe02ca207
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.c
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "display_io.h"
+#include "irq.h"
+
+__IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS =
+ (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE);
+__IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS =
+ (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE |
+ (DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN));
+
+void display_io_init_gpio(void) {
+ // init peripherals
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_FMC_CLK_ENABLE();
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ // LCD_RST/PC14
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Pin = GPIO_PIN_14;
+ // default to keeping display in reset
+ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+#ifdef DISPLAY_TE_PIN
+ // LCD_FMARK (tearing effect)
+ GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Pin = DISPLAY_TE_PIN;
+ HAL_GPIO_Init(DISPLAY_TE_PORT, &GPIO_InitStructure);
+#endif
+
+ GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
+ // LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5
+ GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
+ // LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1
+ GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
+ // LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10
+ GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
+#ifdef USE_DISP_I8080_16BIT_DW
+ // LCD_D8/PE11 LCD_D9/PE12 LCD_D10/PE13 LCD_D11/PE14
+ GPIO_InitStructure.Pin =
+ GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
+ // LCD_D12/PE15
+ GPIO_InitStructure.Pin = GPIO_PIN_15;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
+ // LCD_D13/PD8 LCD_D14/PD9 LCD_D15/PD10
+ GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
+#endif
+}
+
+void display_io_init_fmc(void) {
+ // Reference UM1725 "Description of STM32F4 HAL and LL drivers",
+ // section 64.2.1 "How to use this driver"
+ SRAM_HandleTypeDef external_display_data_sram = {0};
+ external_display_data_sram.Instance = FMC_NORSRAM_DEVICE;
+ external_display_data_sram.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
+ external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
+ external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
+ external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
+#ifdef USE_DISP_I8080_16BIT_DW
+ external_display_data_sram.Init.MemoryDataWidth =
+ FMC_NORSRAM_MEM_BUS_WIDTH_16;
+#elif USE_DISP_I8080_8BIT_DW
+ external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
+#endif
+ external_display_data_sram.Init.BurstAccessMode =
+ FMC_BURST_ACCESS_MODE_DISABLE;
+ external_display_data_sram.Init.WaitSignalPolarity =
+ FMC_WAIT_SIGNAL_POLARITY_LOW;
+ external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
+ external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
+ external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
+ external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+ external_display_data_sram.Init.AsynchronousWait =
+ FMC_ASYNCHRONOUS_WAIT_DISABLE;
+ external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
+ external_display_data_sram.Init.ContinuousClock =
+ FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
+ external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
+
+ // reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
+ FMC_NORSRAM_TimingTypeDef normal_mode_timing = {0};
+ normal_mode_timing.AddressSetupTime = 5;
+ normal_mode_timing.AddressHoldTime = 1; // don't care
+ normal_mode_timing.DataSetupTime = 6;
+ normal_mode_timing.BusTurnAroundDuration = 0; // don't care
+ normal_mode_timing.CLKDivision = 2; // don't care
+ normal_mode_timing.DataLatency = 2; // don't care
+ normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
+
+ HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
+}
+
+#ifdef DISPLAY_TE_INTERRUPT_HANDLER
+void display_io_init_te_interrupt(void) {
+ EXTI_HandleTypeDef EXTI_Handle = {0};
+ EXTI_ConfigTypeDef EXTI_Config = {0};
+ EXTI_Config.GPIOSel = DISPLAY_TE_INTERRUPT_GPIOSEL;
+ EXTI_Config.Line = DISPLAY_TE_INTERRUPT_EXTI_LINE;
+ EXTI_Config.Mode = EXTI_MODE_INTERRUPT;
+ EXTI_Config.Trigger = EXTI_TRIGGER_RISING;
+ HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config);
+
+ // setup interrupt for tearing effect pin
+ HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0);
+}
+#endif
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_io.h b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.h
new file mode 100644
index 000000000..811151159
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_io.h
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef TREZORHAL_DISPLAY_IO_H
+#define TREZORHAL_DISPLAY_IO_H
+
+#include STM32_HAL_H
+#include TREZOR_BOARD
+
+void display_io_init_gpio(void);
+void display_io_init_fmc(void);
+void display_io_init_te_interrupt(void);
+
+#ifndef FMC_BANK1
+#define FMC_BANK1 0x60000000U
+#endif
+
+#define DISPLAY_MEMORY_BASE FMC_BANK1
+#define DISPLAY_MEMORY_PIN 16
+
+#ifdef USE_DISP_I8080_16BIT_DW
+#define DISPLAY_ADDR_SHIFT 2
+#define DISP_MEM_TYPE uint16_t
+#elif USE_DISP_I8080_8BIT_DW
+#define DISPLAY_ADDR_SHIFT 1
+#define DISP_MEM_TYPE uint8_t
+#else
+#error "Unsupported display interface"
+#endif
+
+/*#define DISPLAY_CMD_ADDRESS ((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE))
+#define DISPLAY_DATA_ADDRESS \
+ ((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE | \
+ (DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN)))
+*/
+
+extern __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS;
+extern __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS;
+
+#define ISSUE_CMD_BYTE(X) (*(DISPLAY_CMD_ADDRESS) = (X))
+#define ISSUE_DATA_BYTE(X) (*(DISPLAY_DATA_ADDRESS) = (X))
+
+#ifdef USE_DISP_I8080_16BIT_DW
+#define ISSUE_PIXEL_DATA(X) DATA(X)
+#elif USE_DISP_I8080_8BIT_DW
+#define ISSUE_PIXEL_DATA(X) \
+ ISSUE_DATA_BYTE((X)&0xFF); \
+ ISSUE_DATA_BYTE((X) >> 8)
+#endif
+
+#endif // TREZORHAL_DISPLAY_IO_H
\ No newline at end of file
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.c b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.c
new file mode 100644
index 000000000..001579b87
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.c
@@ -0,0 +1,235 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+// using const volatile instead of #define results in binaries that change
+// only in 1-byte when the flag changes.
+// using #define leads compiler to over-optimize the code leading to bigger
+// differencies in the resulting binaries.
+
+#include "display_panel.h"
+#include "display_io.h"
+
+#ifdef TREZOR_MODEL_T
+#include "panels/154a.h"
+#include "panels/lx154a2411.h"
+#include "panels/lx154a2422.h"
+#include "panels/tf15411a.h"
+#else
+#include "panels/lx154a2422.h"
+#endif
+
+// using const volatile instead of #define results in binaries that change
+// only in 1-byte when the flag changes.
+// using #define leads compiler to over-optimize the code leading to bigger
+// differencies in the resulting binaries.
+const volatile uint8_t DISPLAY_ST7789V_INVERT_COLORS2 = 1;
+
+#ifdef DISPLAY_IDENTIFY
+static uint32_t read_display_id(uint8_t command) {
+ volatile uint8_t c = 0;
+ uint32_t id = 0;
+ ISSUE_CMD_BYTE(command);
+ c = *DISPLAY_DATA_ADDRESS; // first returned value is a dummy value and
+ // should be discarded
+ c = *DISPLAY_DATA_ADDRESS;
+ id |= (c << 16);
+ c = *DISPLAY_DATA_ADDRESS;
+ id |= (c << 8);
+ c = *DISPLAY_DATA_ADDRESS;
+ id |= c;
+ return id;
+}
+
+uint32_t display_panel_identify(void) {
+ static uint32_t id = 0x000000U;
+ static bool id_initialized = false;
+
+ // Return immediately if id has been already initialized
+ if (id_initialized) return id;
+
+ // RDDID: Read Display ID
+ id = read_display_id(0x04);
+ // the default RDDID for ILI9341 should be 0x8000.
+ // some display modules return 0x0.
+ // the ILI9341 has an extra id, let's check it here.
+ if ((id != DISPLAY_ID_ST7789V) && (id != DISPLAY_ID_GC9307)) {
+ // Read ID4
+ uint32_t id4 = read_display_id(0xD3);
+ if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341
+ id = id4;
+ }
+ }
+ id_initialized = true;
+ return id;
+}
+#else
+uint32_t display_panbel_identify(void) { return DISPLAY_ID_ST7789V; }
+#endif
+
+bool display_panel_is_inverted() {
+ bool inv_on = false;
+ uint32_t id = display_panel_identify();
+ if (id == DISPLAY_ID_ST7789V) {
+ volatile uint8_t c = 0;
+ ISSUE_CMD_BYTE(0x09); // read display status
+ c = *DISPLAY_DATA_ADDRESS; // don't care
+ c = *DISPLAY_DATA_ADDRESS; // don't care
+ c = *DISPLAY_DATA_ADDRESS; // don't care
+ c = *DISPLAY_DATA_ADDRESS;
+ if (c & 0x20) {
+ inv_on = true;
+ }
+ c = *DISPLAY_DATA_ADDRESS; // don't care
+ }
+
+ return inv_on;
+}
+
+void display_panel_sleep(void) {
+ uint32_t id = display_panel_identify();
+ if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
+ (id == DISPLAY_ID_ST7789V)) {
+ ISSUE_CMD_BYTE(0x28); // DISPOFF: Display Off
+ ISSUE_CMD_BYTE(0x10); // SLPIN: Sleep in
+ HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before
+ // sending any new commands
+ }
+}
+
+void display_panel_unsleep(void) {
+ uint32_t id = display_panel_identify();
+ if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
+ (id == DISPLAY_ID_ST7789V)) {
+ ISSUE_CMD_BYTE(0x11); // SLPOUT: Sleep Out
+ HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before
+ // sending any new commands
+ ISSUE_CMD_BYTE(0x29); // DISPON: Display On
+ }
+}
+
+void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
+ uint16_t y1) {
+ uint32_t id = display_panel_identify();
+ if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
+ (id == DISPLAY_ID_ST7789V)) {
+ ISSUE_CMD_BYTE(0x2A);
+ ISSUE_DATA_BYTE(x0 >> 8);
+ ISSUE_DATA_BYTE(x0 & 0xFF);
+ ISSUE_DATA_BYTE(x1 >> 8);
+ ISSUE_DATA_BYTE(x1 & 0xFF); // column addr set
+ ISSUE_CMD_BYTE(0x2B);
+ ISSUE_DATA_BYTE(y0 >> 8);
+ ISSUE_DATA_BYTE(y0 & 0xFF);
+ ISSUE_DATA_BYTE(y1 >> 8);
+ ISSUE_DATA_BYTE(y1 & 0xFF); // row addr set
+ ISSUE_CMD_BYTE(0x2C);
+ }
+}
+
+void display_panel_set_little_endian(void) {
+ uint32_t id = display_panel_identify();
+ if (id == DISPLAY_ID_GC9307) {
+ // CANNOT SET ENDIAN FOR GC9307
+ } else if (id == DISPLAY_ID_ST7789V) {
+ ISSUE_CMD_BYTE(0xB0);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0xF8);
+ } else if (id == DISPLAY_ID_ILI9341V) {
+ // Interface Control: XOR BGR as ST7789V does
+ ISSUE_CMD_BYTE(0xF6);
+ ISSUE_DATA_BYTE(0x09);
+ ISSUE_DATA_BYTE(0x30);
+ ISSUE_DATA_BYTE(0x20);
+ }
+}
+
+void display_panel_set_big_endian(void) {
+ uint32_t id = display_panel_identify();
+ if (id == DISPLAY_ID_GC9307) {
+ // CANNOT SET ENDIAN FOR GC9307
+ } else if (id == DISPLAY_ID_ST7789V) {
+ ISSUE_CMD_BYTE(0xB0);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0xF0);
+ } else if (id == DISPLAY_ID_ILI9341V) {
+ // Interface Control: XOR BGR as ST7789V does
+ ISSUE_CMD_BYTE(0xF6);
+ ISSUE_DATA_BYTE(0x09);
+ ISSUE_DATA_BYTE(0x30);
+ ISSUE_DATA_BYTE(0x00);
+ }
+}
+
+void display_panal_init(void) {
+ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14
+ // wait 10 milliseconds. only needs to be low for 10 microseconds.
+ // my dev display module ties display reset and touch panel reset together.
+ // keeping this low for max(display_reset_time, ctpm_reset_time) aids
+ // development and does not hurt.
+ HAL_Delay(10);
+ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); // LCD_RST/PC14
+ // max wait time for hardware reset is 120 milliseconds
+ // (experienced display flakiness using only 5ms wait before sending commands)
+ HAL_Delay(120);
+
+ // identify the controller we will communicate with
+#ifdef TREZOR_MODEL_T
+ uint32_t id = display_panel_identify();
+ if (id == DISPLAY_ID_GC9307) {
+ tf15411a_init_seq();
+ } else if (id == DISPLAY_ID_ST7789V) {
+ if (DISPLAY_ST7789V_INVERT_COLORS2) {
+ lx154a2422_init_seq();
+ } else {
+ lx154a2411_init_seq();
+ }
+ } else if (id == DISPLAY_ID_ILI9341V) {
+ _154a_init_seq();
+ }
+#else
+ lx154a2422_init_seq();
+#endif
+
+ display_panel_unsleep();
+}
+
+void display_panel_init_gamma(void) {
+#ifdef TREZOR_MODEL_T
+ uint32_t id = display_panel_identify();
+ if (id == DISPLAY_ID_ST7789V && display_panel_is_inverted()) {
+ // newest TT display - set proper gamma
+ lx154a2422_gamma();
+ } else if (id == DISPLAY_ID_ST7789V) {
+ lx154a2411_gamma();
+ }
+#endif
+}
+
+void display_panel_rotate(int angle) {
+#ifdef TREZOR_MODEL_T
+ uint32_t id = display_panel_identify();
+ if (id == DISPLAY_ID_GC9307) {
+ tf15411a_rotate(angle);
+ } else {
+ lx154a2422_rotate(angle);
+ }
+#else
+ lx154a2422_rotate(angle);
+#endif
+}
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.h b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.h
new file mode 100644
index 000000000..8e63577c0
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/display_panel.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef TREZORHAL_ST7789_PANEL_H
+#define TREZORHAL_ST7789_PANEL_H
+
+#include
+#include
+
+// section "9.1.3 RDDID (04h): Read Display ID"
+// of ST7789V datasheet
+#define DISPLAY_ID_ST7789V 0x858552U
+// section "6.2.1. Read display identification information (04h)"
+// of GC9307 datasheet
+#define DISPLAY_ID_GC9307 0x009307U
+// section "8.3.23 Read ID4 (D3h)"
+// of ILI9341V datasheet
+#define DISPLAY_ID_ILI9341V 0x009341U
+
+// Identifies the connected display panel and
+// returns one of DISPLAY_ID_xxx constant
+uint32_t display_panel_identify(void);
+bool display_panel_is_inverted();
+
+void display_panel_init(void);
+void display_panel_init_gamma(void);
+void display_panel_set_little_endian(void);
+void display_panel_set_big_endian(void);
+
+void display_panel_sleep(void);
+void display_panel_unsleep(void);
+void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
+ uint16_t y1);
+void display_panel_rotate(int angle);
+
+#endif // TREZORHAL_ST7789_PANEL_H
\ No newline at end of file
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.c
new file mode 100644
index 000000000..8d7dc0fe9
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.c
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "../display_io.h"
+
+void _154a_init_seq(void) {
+ // most recent manual: https://www.newhavendisplay.com/app_notes/ILI9341.pdf
+ // TEON: Tearing Effect Line On; V-blanking only
+ ISSUE_CMD_BYTE(0x35);
+ ISSUE_DATA_BYTE(0x00);
+
+ // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
+ // input)
+ ISSUE_CMD_BYTE(0x3A);
+ ISSUE_DATA_BYTE(0x55);
+
+ // Display Function Control: gate scan direction 319 -> 0
+ ISSUE_CMD_BYTE(0xB6);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0xC2);
+ ISSUE_DATA_BYTE(0x27);
+ ISSUE_DATA_BYTE(0x00);
+
+ // Interface Control: XOR BGR as ST7789V does
+ ISSUE_CMD_BYTE(0xF6);
+ ISSUE_DATA_BYTE(0x09);
+ ISSUE_DATA_BYTE(0x30);
+ ISSUE_DATA_BYTE(0x00);
+
+ // the above config is the most important and definitely necessary
+
+ ISSUE_CMD_BYTE(0xCF);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0xC1);
+ ISSUE_DATA_BYTE(0x30);
+
+ ISSUE_CMD_BYTE(0xED);
+ ISSUE_DATA_BYTE(0x64);
+ ISSUE_DATA_BYTE(0x03);
+ ISSUE_DATA_BYTE(0x12);
+ ISSUE_DATA_BYTE(0x81);
+
+ ISSUE_CMD_BYTE(0xE8);
+ ISSUE_DATA_BYTE(0x85);
+ ISSUE_DATA_BYTE(0x10);
+ ISSUE_DATA_BYTE(0x7A);
+
+ ISSUE_CMD_BYTE(0xF7);
+ ISSUE_DATA_BYTE(0x20);
+
+ ISSUE_CMD_BYTE(0xEA);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x00);
+
+ // power control VRH[5:0]
+ ISSUE_CMD_BYTE(0xC0);
+ ISSUE_DATA_BYTE(0x23);
+
+ // power control SAP[2:0] BT[3:0]
+ ISSUE_CMD_BYTE(0xC1);
+ ISSUE_DATA_BYTE(0x12);
+
+ // vcm control 1
+ ISSUE_CMD_BYTE(0xC5);
+ ISSUE_DATA_BYTE(0x60);
+ ISSUE_DATA_BYTE(0x44);
+
+ // vcm control 2
+ ISSUE_CMD_BYTE(0xC7);
+ ISSUE_DATA_BYTE(0x8A);
+
+ // framerate
+ ISSUE_CMD_BYTE(0xB1);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x18);
+
+ // 3 gamma func disable
+ ISSUE_CMD_BYTE(0xF2);
+ ISSUE_DATA_BYTE(0x00);
+
+ // gamma curve 1
+ ISSUE_CMD_BYTE(0xE0);
+ ISSUE_DATA_BYTE(0x0F);
+ ISSUE_DATA_BYTE(0x2F);
+ ISSUE_DATA_BYTE(0x2C);
+ ISSUE_DATA_BYTE(0x0B);
+ ISSUE_DATA_BYTE(0x0F);
+ ISSUE_DATA_BYTE(0x09);
+ ISSUE_DATA_BYTE(0x56);
+ ISSUE_DATA_BYTE(0xD9);
+ ISSUE_DATA_BYTE(0x4A);
+ ISSUE_DATA_BYTE(0x0B);
+ ISSUE_DATA_BYTE(0x14);
+ ISSUE_DATA_BYTE(0x05);
+ ISSUE_DATA_BYTE(0x0C);
+ ISSUE_DATA_BYTE(0x06);
+ ISSUE_DATA_BYTE(0x00);
+
+ // gamma curve 2
+ ISSUE_CMD_BYTE(0xE1);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x10);
+ ISSUE_DATA_BYTE(0x13);
+ ISSUE_DATA_BYTE(0x04);
+ ISSUE_DATA_BYTE(0x10);
+ ISSUE_DATA_BYTE(0x06);
+ ISSUE_DATA_BYTE(0x25);
+ ISSUE_DATA_BYTE(0x26);
+ ISSUE_DATA_BYTE(0x3B);
+ ISSUE_DATA_BYTE(0x04);
+ ISSUE_DATA_BYTE(0x0B);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x33);
+ ISSUE_DATA_BYTE(0x39);
+ ISSUE_DATA_BYTE(0x0F);
+}
diff --git a/core/embed/gdc/gdc.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.h
similarity index 80%
rename from core/embed/gdc/gdc.h
rename to core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.h
index 20f67638c..410455abb 100644
--- a/core/embed/gdc/gdc.h
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/154a.h
@@ -17,14 +17,11 @@
* along with this program. If not, see .
*/
-#ifndef GDC_H
-#define GDC_H
+#ifndef _154A_H_
+#define _154A_H_
-#include "gdc_bitmap.h"
-#include "gdc_color.h"
-#include "gdc_core.h"
-#include "gdc_geom.h"
-#include "gdc_ops.h"
-#include "gdc_text.h"
+// ILI9341 IC controller
-#endif // GDC_H
+void _154a_init_seq(void);
+
+#endif
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c
new file mode 100644
index 000000000..b81ee75bb
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c
@@ -0,0 +1,82 @@
+
+#include "../display_io.h"
+
+void lx154a2411_gamma(void) {
+ // positive voltage correction
+ ISSUE_CMD_BYTE(0xE0);
+ ISSUE_DATA_BYTE(0xD0);
+ ISSUE_DATA_BYTE(0x03);
+ ISSUE_DATA_BYTE(0x08);
+ ISSUE_DATA_BYTE(0x0E);
+ ISSUE_DATA_BYTE(0x11);
+ ISSUE_DATA_BYTE(0x2B);
+ ISSUE_DATA_BYTE(0x3B);
+ ISSUE_DATA_BYTE(0x44);
+ ISSUE_DATA_BYTE(0x4C);
+ ISSUE_DATA_BYTE(0x2B);
+ ISSUE_DATA_BYTE(0x16);
+ ISSUE_DATA_BYTE(0x15);
+ ISSUE_DATA_BYTE(0x1E);
+ ISSUE_DATA_BYTE(0x21);
+
+ // negative voltage correction
+ ISSUE_CMD_BYTE(0xE1);
+ ISSUE_DATA_BYTE(0xD0);
+ ISSUE_DATA_BYTE(0x03);
+ ISSUE_DATA_BYTE(0x08);
+ ISSUE_DATA_BYTE(0x0E);
+ ISSUE_DATA_BYTE(0x11);
+ ISSUE_DATA_BYTE(0x2B);
+ ISSUE_DATA_BYTE(0x3B);
+ ISSUE_DATA_BYTE(0x54);
+ ISSUE_DATA_BYTE(0x4C);
+ ISSUE_DATA_BYTE(0x2B);
+ ISSUE_DATA_BYTE(0x16);
+ ISSUE_DATA_BYTE(0x15);
+ ISSUE_DATA_BYTE(0x1E);
+ ISSUE_DATA_BYTE(0x21);
+}
+
+void lx154a2411_init_seq(void) {
+ // most recent manual:
+ // https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf
+ // TEON: Tearing Effect Line On; V-blanking only
+ ISSUE_CMD_BYTE(0x35);
+ ISSUE_DATA_BYTE(0x00);
+
+ // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
+ // input)
+ ISSUE_CMD_BYTE(0x3A);
+ ISSUE_DATA_BYTE(0x55);
+
+ // CMD2EN: Commands in command table 2 can be executed when EXTC level is Low
+ ISSUE_CMD_BYTE(0xDF);
+ ISSUE_DATA_BYTE(0x5A);
+ ISSUE_DATA_BYTE(0x69);
+ ISSUE_DATA_BYTE(0x02);
+ ISSUE_DATA_BYTE(0x01);
+
+ // LCMCTRL: LCM Control: XOR RGB setting
+ ISSUE_CMD_BYTE(0xC0);
+ ISSUE_DATA_BYTE(0x20);
+
+ // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.;
+ // gate scan direction 319 -> 0
+ ISSUE_CMD_BYTE(0xE4);
+ ISSUE_DATA_BYTE(0x1D);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x11);
+
+ // INVOFF (20h): Display Inversion Off
+ // INVON (21h): Display Inversion On
+ ISSUE_CMD_BYTE(0x20);
+
+ // the above config is the most important and definitely necessary
+
+ // PWCTRL1: Power Control 1
+ ISSUE_CMD_BYTE(0xD0);
+ ISSUE_DATA_BYTE(0xA4);
+ ISSUE_DATA_BYTE(0xA1);
+
+ lx154a2411_gamma();
+}
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.h
new file mode 100644
index 000000000..347aa3b58
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef LX154A2411_H_
+#define LX154A2411_H_
+
+// ST7789_V IC controller
+void lx154a2411_gamma(void);
+void lx154a2411_init_seq(void);
+
+#endif
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c
new file mode 100644
index 000000000..37d96660a
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c
@@ -0,0 +1,150 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "../display_io.h"
+#include "touch.h"
+
+void lx154a2422_gamma(void) {
+ // positive voltage correction
+ ISSUE_CMD_BYTE(0xE0);
+ ISSUE_DATA_BYTE(0xD0);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x10);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x26);
+ ISSUE_DATA_BYTE(0x36);
+ ISSUE_DATA_BYTE(0x34);
+ ISSUE_DATA_BYTE(0x4D);
+ ISSUE_DATA_BYTE(0x18);
+ ISSUE_DATA_BYTE(0x13);
+ ISSUE_DATA_BYTE(0x14);
+ ISSUE_DATA_BYTE(0x2F);
+ ISSUE_DATA_BYTE(0x34);
+
+ // negative voltage correction
+ ISSUE_CMD_BYTE(0xE1);
+ ISSUE_DATA_BYTE(0xD0);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x10);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x09);
+ ISSUE_DATA_BYTE(0x26);
+ ISSUE_DATA_BYTE(0x36);
+ ISSUE_DATA_BYTE(0x53);
+ ISSUE_DATA_BYTE(0x4C);
+ ISSUE_DATA_BYTE(0x18);
+ ISSUE_DATA_BYTE(0x14);
+ ISSUE_DATA_BYTE(0x14);
+ ISSUE_DATA_BYTE(0x2F);
+ ISSUE_DATA_BYTE(0x34);
+}
+
+void lx154a2422_init_seq(void) {
+ // most recent manual:
+ // https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf
+ // TEON: Tearing Effect Line On; V-blanking only
+ ISSUE_CMD_BYTE(0x35);
+ ISSUE_DATA_BYTE(0x00);
+
+ // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
+ // input)
+ ISSUE_CMD_BYTE(0x3A);
+ ISSUE_DATA_BYTE(0x55);
+
+ // CMD2EN: Commands in command table 2 can be executed when EXTC level is Low
+ ISSUE_CMD_BYTE(0xDF);
+ ISSUE_DATA_BYTE(0x5A);
+ ISSUE_DATA_BYTE(0x69);
+ ISSUE_DATA_BYTE(0x02);
+ ISSUE_DATA_BYTE(0x01);
+
+ // LCMCTRL: LCM Control: XOR RGB setting
+ ISSUE_CMD_BYTE(0xC0);
+ ISSUE_DATA_BYTE(0x20);
+
+ // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.;
+ // gate scan direction 319 -> 0
+ ISSUE_CMD_BYTE(0xE4);
+ ISSUE_DATA_BYTE(0x1D);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x11);
+
+ // INVOFF (20h): Display Inversion Off
+ // INVON (21h): Display Inversion On
+ ISSUE_CMD_BYTE(0x21);
+
+ // the above config is the most important and definitely necessary
+
+ // PWCTRL1: Power Control 1
+ ISSUE_CMD_BYTE(0xD0);
+ ISSUE_DATA_BYTE(0xA4);
+ ISSUE_DATA_BYTE(0xA1);
+
+ lx154a2422_gamma();
+}
+
+void lx154a2422_rotate(int degrees) {
+ uint16_t shift = 0;
+
+#define RGB (1 << 3)
+#define ML (1 << 4) // vertical refresh order
+#define MH (1 << 2) // horizontal refresh order
+#define MV (1 << 5)
+#define MX (1 << 6)
+#define MY (1 << 7)
+ // MADCTL: Memory Data Access Control - reference:
+ // section 8.12 in the ST7789V manual
+ uint8_t display_command_parameter = 0;
+ switch (degrees) {
+ case 0:
+ display_command_parameter = 0;
+ break;
+ case 90:
+ display_command_parameter = MV | MX | MH | ML;
+ shift = 1;
+ break;
+ case 180:
+ display_command_parameter = MX | MY | MH | ML;
+ shift = 1;
+ break;
+ case 270:
+ display_command_parameter = MV | MY;
+ break;
+ }
+
+ ISSUE_CMD_BYTE(0x36);
+ ISSUE_DATA_BYTE(display_command_parameter);
+
+ if (shift) {
+ // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
+ // gate 80.; gate scan direction 319 -> 0
+ ISSUE_CMD_BYTE(0xE4);
+ ISSUE_DATA_BYTE(0x1D);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x11);
+ } else {
+ // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
+ // gate 80.; gate scan direction 319 -> 0
+ ISSUE_CMD_BYTE(0xE4);
+ ISSUE_DATA_BYTE(0x1D);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x11);
+ }
+}
diff --git a/core/embed/gdc/gdc_text.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.h
similarity index 53%
rename from core/embed/gdc/gdc_text.h
rename to core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.h
index e881e5e33..30a13e359 100644
--- a/core/embed/gdc/gdc_text.h
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.h
@@ -17,32 +17,13 @@
* along with this program. If not, see .
*/
-#ifndef GDC_TEXT_H
-#define GDC_TEXT_H
+#ifndef LX154A2422_H_
+#define LX154A2422_H_
-#include "gdc_color.h"
-#include "gdc_core.h"
-#include "gdc_geom.h"
+#include "displays/st7789v.h"
-#include
-#include
+void lx154a2422_init_seq(void);
+void lx154a2422_gamma(void);
+void lx154a2422_rotate(int degrees);
-typedef struct {
- int font;
-
- gdc_color_t fg_color;
- gdc_color_t bg_color;
-
- // TODO: horizontal/vertical alignment??
- // TODO: extra offset???
- gdc_offset_t offset;
-
-} gdc_text_attr_t;
-
-bool gdc_draw_opaque_text(gdc_t* gdc, gdc_rect_t rect, const char* text,
- size_t maxlen, const gdc_text_attr_t* attr);
-
-bool gdc_draw_blended_text(gdc_t* gdc, gdc_rect_t rect, const char* text,
- size_t maxlen, const gdc_text_attr_t* attr);
-
-#endif // GDC_TEXT_H
+#endif
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c
new file mode 100644
index 000000000..cb8e9c7a0
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "../display_io.h"
+
+void tf15411a_init_seq(void) {
+ // Inter Register Enable1
+ ISSUE_CMD_BYTE(0xFE);
+
+ // Inter Register Enable2
+ ISSUE_CMD_BYTE(0xEF);
+
+ // TEON: Tearing Effect Line On; V-blanking only
+ ISSUE_CMD_BYTE(0x35);
+ ISSUE_DATA_BYTE(0x00);
+
+ // COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
+ // input)
+ ISSUE_CMD_BYTE(0x3A);
+ ISSUE_DATA_BYTE(0x55);
+
+ // Frame Rate
+ // ISSUE_CMD_BYTE(0xE8); ISSUE_DATA_BYTE(0x12); ISSUE_DATA_BYTE(0x00);
+
+ // Power Control 2
+ ISSUE_CMD_BYTE(0xC3);
+ ISSUE_DATA_BYTE(0x27);
+
+ // Power Control 3
+ ISSUE_CMD_BYTE(0xC4);
+ ISSUE_DATA_BYTE(0x18);
+
+ // Power Control 4
+ ISSUE_CMD_BYTE(0xC9);
+ ISSUE_DATA_BYTE(0x1F);
+
+ ISSUE_CMD_BYTE(0xC5);
+ ISSUE_DATA_BYTE(0x0F);
+
+ ISSUE_CMD_BYTE(0xC6);
+ ISSUE_DATA_BYTE(0x00);
+
+ ISSUE_CMD_BYTE(0xC7);
+ ISSUE_DATA_BYTE(0x10);
+
+ ISSUE_CMD_BYTE(0xC8);
+ ISSUE_DATA_BYTE(0x01);
+
+ ISSUE_CMD_BYTE(0xFF);
+ ISSUE_DATA_BYTE(0x62);
+
+ ISSUE_CMD_BYTE(0x99);
+ ISSUE_DATA_BYTE(0x3E);
+
+ ISSUE_CMD_BYTE(0x9D);
+ ISSUE_DATA_BYTE(0x4B);
+
+ ISSUE_CMD_BYTE(0x8E);
+ ISSUE_DATA_BYTE(0x0F);
+
+ // SET_GAMMA1
+ ISSUE_CMD_BYTE(0xF0);
+ ISSUE_DATA_BYTE(0x8F);
+ ISSUE_DATA_BYTE(0x1B);
+ ISSUE_DATA_BYTE(0x05);
+ ISSUE_DATA_BYTE(0x06);
+ ISSUE_DATA_BYTE(0x07);
+ ISSUE_DATA_BYTE(0x42);
+
+ // SET_GAMMA3
+ ISSUE_CMD_BYTE(0xF2);
+ ISSUE_DATA_BYTE(0x5C);
+ ISSUE_DATA_BYTE(0x1F);
+ ISSUE_DATA_BYTE(0x12);
+ ISSUE_DATA_BYTE(0x10);
+ ISSUE_DATA_BYTE(0x07);
+ ISSUE_DATA_BYTE(0x43);
+
+ // SET_GAMMA2
+ ISSUE_CMD_BYTE(0xF1);
+ ISSUE_DATA_BYTE(0x59);
+ ISSUE_DATA_BYTE(0xCF);
+ ISSUE_DATA_BYTE(0xCF);
+ ISSUE_DATA_BYTE(0x35);
+ ISSUE_DATA_BYTE(0x37);
+ ISSUE_DATA_BYTE(0x8F);
+
+ // SET_GAMMA4
+ ISSUE_CMD_BYTE(0xF3);
+ ISSUE_DATA_BYTE(0x58);
+ ISSUE_DATA_BYTE(0xCF);
+ ISSUE_DATA_BYTE(0xCF);
+ ISSUE_DATA_BYTE(0x35);
+ ISSUE_DATA_BYTE(0x37);
+ ISSUE_DATA_BYTE(0x8F);
+}
+
+void tf15411a_rotate(int degrees) {
+ uint16_t shift = 0;
+
+#define RGB (1 << 3)
+#define ML (1 << 4) // vertical refresh order
+#define MH (1 << 2) // horizontal refresh order
+#define MV (1 << 5)
+#define MX (1 << 6)
+#define MY (1 << 7)
+ // MADCTL: Memory Data Access Control - reference:
+ // section 9.3 in the ILI9341 manual
+ // section 6.2.18 in the GC9307 manual
+ // section 8.12 in the ST7789V manual
+ uint8_t display_command_parameter = 0;
+ switch (degrees) {
+ case 0:
+ display_command_parameter = 0;
+ break;
+ case 90:
+ display_command_parameter = MV | MX | MH | ML;
+ shift = 1;
+ break;
+ case 180:
+ display_command_parameter = MX | MY | MH | ML;
+ shift = 1;
+ break;
+ case 270:
+ display_command_parameter = MV | MY;
+ break;
+ }
+
+ display_command_parameter ^= RGB | MY; // XOR RGB and MY settings
+
+ ISSUE_CMD_BYTE(0x36);
+ ISSUE_DATA_BYTE(display_command_parameter);
+
+ if (shift) {
+ // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
+ // gate 80.; gate scan direction 319 -> 0
+ ISSUE_CMD_BYTE(0xE4);
+ ISSUE_DATA_BYTE(0x1D);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x11);
+ } else {
+ // GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
+ // gate 80.; gate scan direction 319 -> 0
+ ISSUE_CMD_BYTE(0xE4);
+ ISSUE_DATA_BYTE(0x1D);
+ ISSUE_DATA_BYTE(0x0A);
+ ISSUE_DATA_BYTE(0x11);
+ }
+}
diff --git a/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.h b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.h
new file mode 100644
index 000000000..6ff9e3f7d
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef TF15411A_H_
+#define TF15411A_H_
+
+// GC9307 IC controller
+
+void tf15411a_init_seq(void);
+void tf15411a_rotate(int degrees);
+
+#endif
diff --git a/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c
new file mode 100644
index 000000000..69936d315
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c
@@ -0,0 +1,121 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "display_internal.h"
+#include "ili9341_spi.h"
+#include "xdisplay.h"
+
+#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 320)
+#error "Incompatible display resolution"
+#endif
+
+// Display driver context.
+typedef struct {
+ // Current display orientation (0, 90, 180, 270)
+ int orientation_angle;
+ // Current backlight level ranging from 0 to 255
+ int backlight_level;
+} display_driver_t;
+
+// Display driver instance
+static display_driver_t g_display_driver;
+
+void display_init(void) {
+ display_driver_t *drv = &g_display_driver;
+ memset(drv, 0, sizeof(display_driver_t));
+
+ // Initialize LTDC controller
+ BSP_LCD_Init();
+ // Initialize external display controller
+ ili9341_init();
+}
+
+void display_reinit(void) {
+ display_driver_t *drv = &g_display_driver;
+ memset(drv, 0, sizeof(display_driver_t));
+}
+
+void display_finish_actions(void) {
+ // Not used and intentionally left empty
+}
+
+int display_set_backlight(int level) {
+ display_driver_t *drv = &g_display_driver;
+
+ // Just emulation, not doing anything
+ drv->backlight_level = level;
+ return level;
+}
+
+int display_get_backlight(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return drv->backlight_level;
+}
+
+int display_set_orientation(int angle) {
+ display_driver_t *drv = &g_display_driver;
+
+ if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
+ // Just emulation, not doing anything
+ drv->orientation_angle = angle;
+ }
+
+ return drv->orientation_angle;
+}
+
+int display_get_orientation(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return drv->orientation_angle;
+}
+
+void *display_get_frame_addr(void) { return (void *)FRAME_BUFFER_ADDR; }
+
+void display_refresh(void) {
+ // Do nothing as using just a single frame buffer
+}
+
+const char *display_save(const char *prefix) { return NULL; }
+
+void display_clear_save(void) {}
+
+void display_set_compatible_settings() {}
+
+// Functions for drawing on display
+/*
+
+// Fills a rectangle with a specified color
+void display_fill(gdc_dma2d_t *dp);
+
+// Copies an RGB565 bitmap to specified rectangle
+void display_copy_rgb565(gdc_dma2d_t *dp);
+
+// Copies a MONO4 bitmap to specified rectangle
+void display_copy_mono4(gdc_dma2d_t *dp);
+
+// Copies a MONO1P bitmap to specified rectangle
+void display_copy_mono1p(gdc_dma2d_t *dp);
+*/
diff --git a/core/embed/gdc/gdc_dma2d.h b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_internal.h
similarity index 55%
rename from core/embed/gdc/gdc_dma2d.h
rename to core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_internal.h
index 13d922c00..c19c63a65 100644
--- a/core/embed/gdc/gdc_dma2d.h
+++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_internal.h
@@ -17,35 +17,20 @@
* along with this program. If not, see .
*/
-#ifndef GDC_DMA2D_H
-#define GDC_DMA2D_H
+#ifndef TREZORHAL_DISPLAY_INTERNAL_H
+#define TREZORHAL_DISPLAY_INTERNAL_H
-#include
-#include
+#include TREZOR_BOARD
+#include STM32_HAL_H
-#include "gdc_color.h"
+#include "sdram.h"
-typedef struct {
- // Destination bitma[
- // Following fields are used for all operations
- uint16_t height;
- uint16_t width;
- void* dst_row;
- uint16_t dst_x;
- uint16_t dst_y;
- uint16_t dst_stride;
+// Frame buffer address in external SDRAM
+#define FRAME_BUFFER_ADDR ((uint32_t)SDRAM_DEVICE_ADDR)
+// Frame buffer size (16-bit per pixel RGB565)
+#define FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2)
- // Source bitmap
- // Used for copying and blending, but src_fg & src_alpha
- // fields are also used for fill operation
- void* src_row;
- uint16_t src_x;
- uint16_t src_y;
- uint16_t src_stride;
- gdc_color_t src_fg;
- gdc_color_t src_bg;
- uint8_t src_alpha;
+// Initializes LTDC controller and I/O pins
+void BSP_LCD_Init(void);
-} dma2d_params_t;
-
-#endif // GDC_DMA2D_H
\ No newline at end of file
+#endif // TREZORHAL_DISPLAY_INTERNAL_H
diff --git a/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c
new file mode 100644
index 000000000..df3a752c3
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "display_internal.h"
+#include "ili9341_spi.h"
+#include "xdisplay.h"
+
+#define MAX_LAYER_NUMBER 2
+
+LTDC_HandleTypeDef LtdcHandler;
+static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
+
+/* Default LCD configuration with LCD Layer 1 */
+uint32_t ActiveLayer = 0;
+
+/**
+ * @brief Initializes the LCD layers.
+ * @param LayerIndex: the layer foreground or background.
+ * @param FB_Address: the layer frame buffer.
+ */
+void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
+ LTDC_LayerCfgTypeDef Layercfg;
+
+ /* Layer Init */
+ Layercfg.WindowX0 = 0;
+ Layercfg.WindowX1 = DISPLAY_RESX;
+ Layercfg.WindowY0 = 0;
+ Layercfg.WindowY1 = DISPLAY_RESY;
+ Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
+ Layercfg.FBStartAdress = FB_Address;
+ Layercfg.Alpha = 255;
+ Layercfg.Alpha0 = 0;
+ Layercfg.Backcolor.Blue = 0;
+ Layercfg.Backcolor.Green = 0;
+ Layercfg.Backcolor.Red = 0;
+ Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
+ Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
+ Layercfg.ImageWidth = DISPLAY_RESX;
+ Layercfg.ImageHeight = DISPLAY_RESY;
+
+ HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex);
+
+ // DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE;
+ // DrawProp[LayerIndex].pFont = &Font24;
+ // DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK;
+
+ /* Dithering activation */
+ HAL_LTDC_EnableDither(&LtdcHandler);
+}
+
+/**
+ * @brief Selects the LCD Layer.
+ * @param LayerIndex: the Layer foreground or background.
+ */
+void BSP_LCD_SelectLayer(uint32_t LayerIndex) { ActiveLayer = LayerIndex; }
+
+/**
+ * @brief Sets a LCD Layer visible.
+ * @param LayerIndex: the visible Layer.
+ * @param state: new state of the specified layer.
+ * This parameter can be: ENABLE or DISABLE.
+ */
+void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState state) {
+ if (state == ENABLE) {
+ __HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
+ } else {
+ __HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
+ }
+ __HAL_LTDC_RELOAD_CONFIG(&LtdcHandler);
+}
+
+/**
+ * @brief Sets an LCD Layer visible without reloading.
+ * @param LayerIndex: Visible Layer
+ * @param State: New state of the specified layer
+ * This parameter can be one of the following values:
+ * @arg ENABLE
+ * @arg DISABLE
+ * @retval None
+ */
+void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex,
+ FunctionalState State) {
+ if (State == ENABLE) {
+ __HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
+ } else {
+ __HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
+ }
+ /* Do not Sets the Reload */
+}
+
+/**
+ * @brief Configures the Transparency.
+ * @param LayerIndex: the Layer foreground or background.
+ * @param Transparency: the Transparency,
+ * This parameter must range from 0x00 to 0xFF.
+ */
+void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) {
+ HAL_LTDC_SetAlpha(&LtdcHandler, Transparency, LayerIndex);
+}
+
+/**
+ * @brief Configures the transparency without reloading.
+ * @param LayerIndex: Layer foreground or background.
+ * @param Transparency: Transparency
+ * This parameter must be a number between Min_Data = 0x00 and
+ * Max_Data = 0xFF
+ * @retval None
+ */
+void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex,
+ uint8_t Transparency) {
+ HAL_LTDC_SetAlpha_NoReload(&LtdcHandler, Transparency, LayerIndex);
+}
+
+/**
+ * @brief Sets a LCD layer frame buffer address.
+ * @param LayerIndex: specifies the Layer foreground or background
+ * @param Address: new LCD frame buffer value
+ */
+void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) {
+ HAL_LTDC_SetAddress(&LtdcHandler, Address, LayerIndex);
+}
+
+/**
+ * @brief Sets an LCD layer frame buffer address without reloading.
+ * @param LayerIndex: Layer foreground or background
+ * @param Address: New LCD frame buffer value
+ * @retval None
+ */
+void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) {
+ HAL_LTDC_SetAddress_NoReload(&LtdcHandler, Address, LayerIndex);
+}
+
+void BSP_LCD_Init(void) {
+ GPIO_InitTypeDef GPIO_InitStructure = {0};
+
+ /* Enable the LTDC and DMA2D Clock */
+ __HAL_RCC_LTDC_CLK_ENABLE();
+ __HAL_RCC_DMA2D_CLK_ENABLE();
+
+ /* Enable GPIOs clock */
+ __HAL_RCC_GPIOA_CLK_ENABLE();
+ __HAL_RCC_GPIOB_CLK_ENABLE();
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOF_CLK_ENABLE();
+ __HAL_RCC_GPIOG_CLK_ENABLE();
+
+ /* GPIOs Configuration */
+ /*
+ +------------------------+-----------------------+----------------------------+
+ + LCD pins assignment +
+ +------------------------+-----------------------+----------------------------+
+ | LCD_TFT R2 <-> PC.10 | LCD_TFT G2 <-> PA.06 | LCD_TFT B2 <-> PD.06 | |
+ LCD_TFT R3 <-> PB.00 | LCD_TFT G3 <-> PG.10 | LCD_TFT B3 <-> PG.11 |
+ | LCD_TFT R4 <-> PA.11 | LCD_TFT G4 <-> PB.10 | LCD_TFT B4 <-> PG.12 | |
+ LCD_TFT R5 <-> PA.12 | LCD_TFT G5 <-> PB.11 | LCD_TFT B5 <-> PA.03 |
+ | LCD_TFT R6 <-> PB.01 | LCD_TFT G6 <-> PC.07 | LCD_TFT B6 <-> PB.08 | |
+ LCD_TFT R7 <-> PG.06 | LCD_TFT G7 <-> PD.03 | LCD_TFT B7 <-> PB.09 |
+ -------------------------------------------------------------------------------
+ | LCD_TFT HSYNC <-> PC.06 | LCDTFT VSYNC <-> PA.04 |
+ | LCD_TFT CLK <-> PG.07 | LCD_TFT DE <-> PF.10 |
+ -----------------------------------------------------
+ */
+
+ /* GPIOA configuration */
+ GPIO_InitStructure.Pin =
+ GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_11 | GPIO_PIN_12;
+ GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
+ GPIO_InitStructure.Alternate = GPIO_AF14_LTDC;
+ HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+ /* GPIOB configuration */
+ GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ /* GPIOC configuration */
+ GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10;
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+ /* GPIOD configuration */
+ GPIO_InitStructure.Pin = GPIO_PIN_3 | GPIO_PIN_6;
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
+
+ /* GPIOF configuration */
+ GPIO_InitStructure.Pin = GPIO_PIN_10;
+ HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);
+
+ /* GPIOG configuration */
+ GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_11;
+ HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
+
+ /* GPIOB configuration */
+ GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1;
+ GPIO_InitStructure.Alternate = GPIO_AF9_LTDC;
+ HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+ /* GPIOG configuration */
+ GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_12;
+ HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
+
+ /* On STM32F429I-DISCO, it is not possible to read ILI9341 ID because */
+ /* PIN EXTC is not connected to VDD and then LCD_READ_ID4 is not accessible.
+ */
+ /* In this case, ReadID function is bypassed.*/
+ /*if(ili9341_drv.ReadID() == ILI9341_ID)*/
+
+ /* LTDC Configuration ----------------------------------------------------*/
+ LtdcHandler.Instance = LTDC;
+
+ /* Timing configuration (Typical configuration from ILI9341 datasheet)
+ HSYNC=10 (9+1)
+ HBP=20 (29-10+1)
+ ActiveW=240 (269-20-10+1)
+ HFP=10 (279-240-20-10+1)
+
+ VSYNC=2 (1+1)
+ VBP=2 (3-2+1)
+ ActiveH=320 (323-2-2+1)
+ VFP=4 (327-320-2-2+1)
+ */
+
+ /* Configure horizontal synchronization width */
+ LtdcHandler.Init.HorizontalSync = ILI9341_HSYNC;
+ /* Configure vertical synchronization height */
+ LtdcHandler.Init.VerticalSync = ILI9341_VSYNC;
+ /* Configure accumulated horizontal back porch */
+ LtdcHandler.Init.AccumulatedHBP = ILI9341_HBP;
+ /* Configure accumulated vertical back porch */
+ LtdcHandler.Init.AccumulatedVBP = ILI9341_VBP;
+ /* Configure accumulated active width */
+ LtdcHandler.Init.AccumulatedActiveW = 269;
+ /* Configure accumulated active height */
+ LtdcHandler.Init.AccumulatedActiveH = 323;
+ /* Configure total width */
+ LtdcHandler.Init.TotalWidth = 279;
+ /* Configure total height */
+ LtdcHandler.Init.TotalHeigh = 327;
+
+ /* Configure R,G,B component values for LCD background color */
+ LtdcHandler.Init.Backcolor.Red = 0;
+ LtdcHandler.Init.Backcolor.Blue = 0;
+ LtdcHandler.Init.Backcolor.Green = 0;
+
+ /* LCD clock configuration */
+ /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
+ /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */
+ /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 Mhz */
+ /* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_8 = 48/4 = 6Mhz */
+ PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
+ PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
+ PeriphClkInitStruct.PLLSAI.PLLSAIR = 4;
+ PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;
+ HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
+
+ /* Polarity */
+ LtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL;
+ LtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL;
+ LtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL;
+ LtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
+
+ HAL_LTDC_Init(&LtdcHandler);
+
+ /* Initialize the LCD Layers */
+ BSP_LCD_LayerDefaultInit(1, FRAME_BUFFER_ADDR);
+
+ memset((void *)FRAME_BUFFER_ADDR, 0, FRAME_BUFFER_SIZE);
+}
diff --git a/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c
new file mode 100644
index 000000000..309fb3f0d
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c
@@ -0,0 +1,512 @@
+
+
+#include
+#include TREZOR_BOARD
+#include "ili9341_spi.h"
+#include STM32_HAL_H
+
+/**
+ * @brief ILI9341 chip IDs
+ */
+#define ILI9341_ID 0x9341
+
+/**
+ * @brief ILI9341 Size
+ */
+#define ILI9341_LCD_PIXEL_WIDTH ((uint16_t)240)
+#define ILI9341_LCD_PIXEL_HEIGHT ((uint16_t)320)
+
+/**
+ * @brief ILI9341 Timing
+ */
+/* Timing configuration (Typical configuration from ILI9341 datasheet)
+ HSYNC=10 (9+1)
+ HBP=20 (29-10+1)
+ ActiveW=240 (269-20-10+1)
+ HFP=10 (279-240-20-10+1)
+
+ VSYNC=2 (1+1)
+ VBP=2 (3-2+1)
+ ActiveH=320 (323-2-2+1)
+ VFP=4 (327-320-2-2+1)
+*/
+
+/**
+ * @brief ILI9341 Registers
+ */
+
+/* Level 1 Commands */
+#define LCD_SWRESET 0x01 /* Software Reset */
+#define LCD_READ_DISPLAY_ID 0x04 /* Read display identification information */
+#define LCD_RDDST 0x09 /* Read Display Status */
+#define LCD_RDDPM 0x0A /* Read Display Power Mode */
+#define LCD_RDDMADCTL 0x0B /* Read Display MADCTL */
+#define LCD_RDDCOLMOD 0x0C /* Read Display Pixel Format */
+#define LCD_RDDIM 0x0D /* Read Display Image Format */
+#define LCD_RDDSM 0x0E /* Read Display Signal Mode */
+#define LCD_RDDSDR 0x0F /* Read Display Self-Diagnostic Result */
+#define LCD_SPLIN 0x10 /* Enter Sleep Mode */
+#define LCD_SLEEP_OUT 0x11 /* Sleep out register */
+#define LCD_PTLON 0x12 /* Partial Mode ON */
+#define LCD_NORMAL_MODE_ON 0x13 /* Normal Display Mode ON */
+#define LCD_DINVOFF 0x20 /* Display Inversion OFF */
+#define LCD_DINVON 0x21 /* Display Inversion ON */
+#define LCD_GAMMA 0x26 /* Gamma register */
+#define LCD_DISPLAY_OFF 0x28 /* Display off register */
+#define LCD_DISPLAY_ON 0x29 /* Display on register */
+#define LCD_COLUMN_ADDR 0x2A /* Colomn address register */
+#define LCD_PAGE_ADDR 0x2B /* Page address register */
+#define LCD_GRAM 0x2C /* GRAM register */
+#define LCD_RGBSET 0x2D /* Color SET */
+#define LCD_RAMRD 0x2E /* Memory Read */
+#define LCD_PLTAR 0x30 /* Partial Area */
+#define LCD_VSCRDEF 0x33 /* Vertical Scrolling Definition */
+#define LCD_TEOFF 0x34 /* Tearing Effect Line OFF */
+#define LCD_TEON 0x35 /* Tearing Effect Line ON */
+#define LCD_MAC 0x36 /* Memory Access Control register*/
+#define LCD_VSCRSADD 0x37 /* Vertical Scrolling Start Address */
+#define LCD_IDMOFF 0x38 /* Idle Mode OFF */
+#define LCD_IDMON 0x39 /* Idle Mode ON */
+#define LCD_PIXEL_FORMAT 0x3A /* Pixel Format register */
+#define LCD_WRITE_MEM_CONTINUE 0x3C /* Write Memory Continue */
+#define LCD_READ_MEM_CONTINUE 0x3E /* Read Memory Continue */
+#define LCD_SET_TEAR_SCANLINE 0x44 /* Set Tear Scanline */
+#define LCD_GET_SCANLINE 0x45 /* Get Scanline */
+#define LCD_WDB 0x51 /* Write Brightness Display register */
+#define LCD_RDDISBV 0x52 /* Read Display Brightness */
+#define LCD_WCD 0x53 /* Write Control Display register*/
+#define LCD_RDCTRLD 0x54 /* Read CTRL Display */
+#define LCD_WRCABC 0x55 /* Write Content Adaptive Brightness Control */
+#define LCD_RDCABC 0x56 /* Read Content Adaptive Brightness Control */
+#define LCD_WRITE_CABC 0x5E /* Write CABC Minimum Brightness */
+#define LCD_READ_CABC 0x5F /* Read CABC Minimum Brightness */
+#define LCD_READ_ID1 0xDA /* Read ID1 */
+#define LCD_READ_ID2 0xDB /* Read ID2 */
+#define LCD_READ_ID3 0xDC /* Read ID3 */
+
+/* Level 2 Commands */
+#define LCD_RGB_INTERFACE 0xB0 /* RGB Interface Signal Control */
+#define LCD_FRMCTR1 0xB1 /* Frame Rate Control (In Normal Mode) */
+#define LCD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle Mode) */
+#define LCD_FRMCTR3 0xB3 /* Frame Rate Control (In Partial Mode) */
+#define LCD_INVTR 0xB4 /* Display Inversion Control */
+#define LCD_BPC 0xB5 /* Blanking Porch Control register */
+#define LCD_DFC 0xB6 /* Display Function Control register */
+#define LCD_ETMOD 0xB7 /* Entry Mode Set */
+#define LCD_BACKLIGHT1 0xB8 /* Backlight Control 1 */
+#define LCD_BACKLIGHT2 0xB9 /* Backlight Control 2 */
+#define LCD_BACKLIGHT3 0xBA /* Backlight Control 3 */
+#define LCD_BACKLIGHT4 0xBB /* Backlight Control 4 */
+#define LCD_BACKLIGHT5 0xBC /* Backlight Control 5 */
+#define LCD_BACKLIGHT7 0xBE /* Backlight Control 7 */
+#define LCD_BACKLIGHT8 0xBF /* Backlight Control 8 */
+#define LCD_POWER1 0xC0 /* Power Control 1 register */
+#define LCD_POWER2 0xC1 /* Power Control 2 register */
+#define LCD_VCOM1 0xC5 /* VCOM Control 1 register */
+#define LCD_VCOM2 0xC7 /* VCOM Control 2 register */
+#define LCD_NVMWR 0xD0 /* NV Memory Write */
+#define LCD_NVMPKEY 0xD1 /* NV Memory Protection Key */
+#define LCD_RDNVM 0xD2 /* NV Memory Status Read */
+#define LCD_READ_ID4 0xD3 /* Read ID4 */
+#define LCD_PGAMMA 0xE0 /* Positive Gamma Correction register */
+#define LCD_NGAMMA 0xE1 /* Negative Gamma Correction register */
+#define LCD_DGAMCTRL1 0xE2 /* Digital Gamma Control 1 */
+#define LCD_DGAMCTRL2 0xE3 /* Digital Gamma Control 2 */
+#define LCD_INTERFACE 0xF6 /* Interface control register */
+
+/* Extend register commands */
+#define LCD_POWERA 0xCB /* Power control A register */
+#define LCD_POWERB 0xCF /* Power control B register */
+#define LCD_DTCA 0xE8 /* Driver timing control A */
+#define LCD_DTCB 0xEA /* Driver timing control B */
+#define LCD_POWER_SEQ 0xED /* Power on sequence register */
+#define LCD_3GAMMA_EN 0xF2 /* 3 Gamma enable register */
+#define LCD_PRC 0xF7 /* Pump ratio control register */
+
+/* Size of read registers */
+#define LCD_READ_ID4_SIZE 3 /* Size of Read ID4 */
+
+/*############################### SPIx #######################################*/
+#define DISCOVERY_SPIx SPI5
+#define DISCOVERY_SPIx_CLK_ENABLE() __HAL_RCC_SPI5_CLK_ENABLE()
+#define DISCOVERY_SPIx_GPIO_PORT GPIOF /* GPIOF */
+#define DISCOVERY_SPIx_AF GPIO_AF5_SPI5
+#define DISCOVERY_SPIx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE()
+#define DISCOVERY_SPIx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE()
+#define DISCOVERY_SPIx_SCK_PIN GPIO_PIN_7 /* PF.07 */
+#define DISCOVERY_SPIx_MISO_PIN GPIO_PIN_8 /* PF.08 */
+#define DISCOVERY_SPIx_MOSI_PIN GPIO_PIN_9 /* PF.09 */
+/* Maximum Timeout values for flags waiting loops. These timeouts are not based
+ on accurate values, they just guarantee that the application will not remain
+ stuck if the SPI communication is corrupted.
+ You may modify these timeout values depending on CPU frequency and
+ application conditions (interrupts routines ...). */
+#define SPIx_TIMEOUT_MAX ((uint32_t)0x1000)
+
+/*################################ LCD #######################################*/
+/* Chip Select macro definition */
+#define LCD_CS_LOW() \
+ HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_RESET)
+#define LCD_CS_HIGH() \
+ HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_SET)
+
+/* Set WRX High to send data */
+#define LCD_WRX_LOW() \
+ HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_RESET)
+#define LCD_WRX_HIGH() \
+ HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_SET)
+
+/* Set WRX High to send data */
+#define LCD_RDX_LOW() \
+ HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_RESET)
+#define LCD_RDX_HIGH() \
+ HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_SET)
+
+/**
+ * @brief LCD Control pin
+ */
+#define LCD_NCS_PIN GPIO_PIN_2
+#define LCD_NCS_GPIO_PORT GPIOC
+#define LCD_NCS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
+#define LCD_NCS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
+/**
+ * @}
+ */
+/**
+ * @brief LCD Command/data pin
+ */
+#define LCD_WRX_PIN GPIO_PIN_13
+#define LCD_WRX_GPIO_PORT GPIOD
+#define LCD_WRX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
+#define LCD_WRX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
+
+#define LCD_RDX_PIN GPIO_PIN_12
+#define LCD_RDX_GPIO_PORT GPIOD
+#define LCD_RDX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
+#define LCD_RDX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
+
+static SPI_HandleTypeDef SpiHandle;
+uint32_t SpixTimeout =
+ SPIx_TIMEOUT_MAX; /*.
+ */
+
+#include
+#include
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "xdisplay.h"
+
+#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 128)
+#error "Incompatible display resolution"
+#endif
+
+// This file implements display driver for monochromatic display V-2864KSWEG01
+// with 128x128 resolution connected to CPU via SPI interface.
+//
+// This type of displayed was used on some preliminary dev kits for T3T1 (Trezor
+// TS3)
+
+// Display driver context.
+typedef struct {
+ // Frame buffer (8-bit Mono)
+ uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY];
+ // Current display orientation (0 or 180)
+ int orientation_angle;
+ // Current backlight level ranging from 0 to 255
+ int backlight_level;
+} display_driver_t;
+
+// Display driver instance
+static display_driver_t g_display_driver;
+
+// Macros to access display parallel interface
+
+// FSMC/FMC Bank 1 - NOR/PSRAM 1
+#define DISPLAY_MEMORY_BASE 0x60000000
+#define DISPLAY_MEMORY_PIN 16
+
+#define CMD_ADDR *((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE)))
+#define DATA_ADDR \
+ (*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | \
+ (1 << DISPLAY_MEMORY_PIN)))))
+
+#define ISSUE_CMD_BYTE(X) \
+ do { \
+ (CMD_ADDR) = (X); \
+ } while (0)
+#define ISSUE_DATA_BYTE(X) \
+ do { \
+ (DATA_ADDR) = (X); \
+ } while (0)
+
+// ---------------------------------------------------------------------------
+// Display controller registers
+// ---------------------------------------------------------------------------
+
+#define OLED_SETCONTRAST 0x81
+#define OLED_DISPLAYALLON_RESUME 0xA4
+#define OLED_DISPLAYALLON 0xA5
+#define OLED_NORMALDISPLAY 0xA6
+#define OLED_INVERTDISPLAY 0xA7
+#define OLED_DISPLAYOFF 0xAE
+#define OLED_DISPLAYON 0xAF
+#define OLED_SETDISPLAYOFFSET 0xD3
+#define OLED_SETCOMPINS 0xDA
+#define OLED_SETVCOMDETECT 0xDB
+#define OLED_SETDISPLAYCLOCKDIV 0xD5
+#define OLED_SETPRECHARGE 0xD9
+#define OLED_SETMULTIPLEX 0xA8
+#define OLED_SETLOWCOLUMN 0x00
+#define OLED_SETHIGHCOLUMN 0x10
+#define OLED_SETSTARTLINE 0x40
+#define OLED_MEMORYMODE 0x20
+#define OLED_COMSCANINC 0xC0
+#define OLED_COMSCANDEC 0xC8
+#define OLED_SEGREMAP 0xA0
+#define OLED_CHARGEPUMP 0x8D
+
+// Dipslay specific initialization sequence
+static const uint8_t ug_2828tswig01_init_seq[] = {
+ OLED_DISPLAYOFF,
+ // Divide ratio 0, Oscillator Frequency +0%
+ OLED_SETDISPLAYCLOCKDIV, 0x50,
+ // Set Memory Addressing Mode - page addressing mode
+ 0x20,
+ // Set Contrast Control Register
+ OLED_SETCONTRAST, 0x8F,
+ // Set DC-DC Setting: (Double Bytes Command)
+ 0xAD, 0x8A,
+ // Set Segment Re-map
+ OLED_SEGREMAP | 0x01,
+ // Set COM Output Scan Direction
+ OLED_COMSCANDEC,
+ // Set Display Start Line:(Double Bytes Command)
+ 0xDC, 0x00,
+ // Set Display Offset:(Double Bytes Command)
+ OLED_SETDISPLAYOFFSET, 0x00,
+ // Set Discharge / Pre-Charge Period (Double Bytes Command)
+ OLED_SETPRECHARGE, 0x22,
+ // Set VCOM Deselect Level
+ OLED_SETVCOMDETECT, 0x35,
+ // Set Multiplex Ratio
+ OLED_SETMULTIPLEX, 0x7F,
+ // Set Page
+ 0xB0,
+ // Reset column
+ OLED_SETLOWCOLUMN | 0, OLED_SETHIGHCOLUMN | 0,
+
+ // Set Entire Display Off
+ // to be clear, this command turns off the function
+ // which turns entire display on, but it does not clear
+ // the data in display RAM
+ OLED_DISPLAYALLON_RESUME,
+ // Set Normal Display
+ OLED_NORMALDISPLAY};
+
+static void __attribute__((unused)) display_sleep(void) {
+ // Display OFF
+ ISSUE_CMD_BYTE(OLED_DISPLAYOFF);
+ HAL_Delay(5);
+ // Vpp disable
+ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET);
+}
+
+static void display_resume(void) {
+ // Vpp enable
+ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_SET);
+ // 100 ms mandatory wait
+ HAL_Delay(100);
+ // Display ON
+ ISSUE_CMD_BYTE(OLED_DISPLAYON);
+}
+
+// Sets the display cursor to the specific row and column
+static void display_set_page_and_col(uint8_t page, uint8_t col) {
+ if (page < (DISPLAY_RESY / 8)) {
+ ISSUE_CMD_BYTE(0xB0 | (page & 0xF));
+
+ if (col < DISPLAY_RESX) {
+ ISSUE_CMD_BYTE(OLED_SETHIGHCOLUMN | ((col & 0x70) >> 4));
+ ISSUE_CMD_BYTE(OLED_SETLOWCOLUMN | (col & 0x0F));
+ } else {
+ // Reset column to start
+ ISSUE_CMD_BYTE(OLED_SETHIGHCOLUMN);
+ ISSUE_CMD_BYTE(OLED_SETLOWCOLUMN);
+ }
+ }
+}
+
+#define COLLECT_ROW_BYTE(src) \
+ (0 | (*(src + (0 * DISPLAY_RESX)) ? 128 : 0) | \
+ (*(src + (1 * DISPLAY_RESX)) ? 64 : 0) | \
+ (*(src + (2 * DISPLAY_RESX)) ? 32 : 0) | \
+ (*(src + (3 * DISPLAY_RESX)) ? 16 : 0) | \
+ (*(src + (4 * DISPLAY_RESX)) ? 8 : 0) | \
+ (*(src + (5 * DISPLAY_RESX)) ? 4 : 0) | \
+ (*(src + (6 * DISPLAY_RESX)) ? 2 : 0) | \
+ (*(src + (7 * DISPLAY_RESX)) ? 1 : 0))
+
+// Copies the framebuffer to the display via SPI interface
+static void display_sync_with_fb(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ for (int y = 0; y < DISPLAY_RESY / 8; y++) {
+ display_set_page_and_col(y, 0);
+ uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8];
+ for (int x = 0; x < DISPLAY_RESX; x++) {
+ ISSUE_DATA_BYTE(COLLECT_ROW_BYTE(src));
+ src++;
+ }
+ }
+}
+
+static void display_init_controller(void) {
+ // LCD_RST/PC14
+ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
+ // wait 10 milliseconds. only needs to be low for 10 microseconds.
+ // my dev display module ties display reset and touch panel reset together.
+ // keeping this low for max(display_reset_time, ctpm_reset_time) aids
+ // development and does not hurt.
+ HAL_Delay(10);
+
+ // LCD_RST/PC14
+ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET);
+ // max wait time for hardware reset is 120 milliseconds
+ // (experienced display flakiness using only 5ms wait before sending commands)
+ HAL_Delay(120);
+
+ // Apply initialization sequence specific to this display controller/panel
+ for (int i = 0; i < sizeof(ug_2828tswig01_init_seq); i++) {
+ ISSUE_CMD_BYTE(ug_2828tswig01_init_seq[i]);
+ }
+
+ // Resume the suspended display
+ display_resume();
+ // Clear display internal framebuffer
+ display_sync_with_fb();
+}
+
+static void display_init_interface(void) {
+ // init peripherals
+ __HAL_RCC_GPIOC_CLK_ENABLE();
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOE_CLK_ENABLE();
+ __HAL_RCC_FMC_CLK_ENABLE();
+
+ GPIO_InitTypeDef GPIO_InitStructure = {0};
+
+ // LCD_RST/PC14
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Pin = GPIO_PIN_14;
+ // default to keeping display in reset
+ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
+ HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
+
+ // VPP Enable
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStructure.Pull = GPIO_PULLDOWN;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Pin = GPIO_PIN_8;
+ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET);
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
+
+ GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
+ // LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5
+ GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
+ // LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1
+ GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
+ // LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10
+ GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
+ HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
+
+ // Reference UM1725 "Description of STM32F4 HAL and LL drivers",
+ // section 64.2.1 "How to use this driver"
+ SRAM_HandleTypeDef display_sram = {0};
+ display_sram.Instance = FMC_NORSRAM_DEVICE;
+ display_sram.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
+ display_sram.Init.NSBank = FMC_NORSRAM_BANK1;
+ display_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
+ display_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
+ display_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
+ display_sram.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE;
+ display_sram.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW;
+ display_sram.Init.WrapMode = FMC_WRAP_MODE_DISABLE;
+ display_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
+ display_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
+ display_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
+ display_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+ display_sram.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
+ display_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
+ display_sram.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
+ display_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
+
+ // reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
+ FMC_NORSRAM_TimingTypeDef normal_mode_timing = {0};
+ normal_mode_timing.AddressSetupTime = 10;
+ normal_mode_timing.AddressHoldTime = 10;
+ normal_mode_timing.DataSetupTime = 10;
+ normal_mode_timing.BusTurnAroundDuration = 0;
+ normal_mode_timing.CLKDivision = 2;
+ normal_mode_timing.DataLatency = 2;
+ normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
+
+ HAL_SRAM_Init(&display_sram, &normal_mode_timing, NULL);
+}
+
+void display_init(void) {
+ display_driver_t *drv = &g_display_driver;
+ memset(drv, 0, sizeof(display_driver_t));
+
+ // Initialize GPIO & FSMC controller
+ display_init_interface();
+ // Initialize display controller
+ display_init_controller();
+}
+
+void display_reinit(void) {
+ display_driver_t *drv = &g_display_driver;
+ memset(drv, 0, sizeof(display_driver_t));
+
+ // !@# TODO backlight level??
+}
+
+void display_finish_actions(void) {
+ /// Not used and intentionally left empty
+}
+
+int display_set_backlight(int level) {
+ display_driver_t *drv = &g_display_driver;
+
+ if (level != drv->backlight_level) {
+ if (level >= 0 && level <= 255) {
+ drv->backlight_level = level;
+ // Set Contrast Control Register: (Double Bytes Command)
+ ISSUE_CMD_BYTE(OLED_SETCONTRAST);
+ ISSUE_CMD_BYTE(level & 0xFF);
+ }
+ }
+
+ return drv->backlight_level;
+}
+
+int display_get_backlight(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return drv->backlight_level;
+}
+
+int display_set_orientation(int angle) {
+ display_driver_t *drv = &g_display_driver;
+
+ if (angle != drv->orientation_angle) {
+ if (angle == 0 || angle == 180) {
+ drv->orientation_angle = angle;
+ if (angle == 0) {
+ // Set Segment Re-map: (A0H - A1H)
+ ISSUE_CMD_BYTE(OLED_SEGREMAP | 0x01);
+ // Set COM Output Scan Direction
+ ISSUE_CMD_BYTE(OLED_COMSCANDEC);
+ } else {
+ // Set Segment Re-map: (A0H - A1H)
+ ISSUE_CMD_BYTE(OLED_SEGREMAP | 0x00);
+ // Set COM Output Scan Direction
+ ISSUE_CMD_BYTE(OLED_COMSCANINC);
+ }
+ }
+ }
+
+ return drv->orientation_angle;
+}
+
+int display_get_orientation(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return drv->orientation_angle;
+}
+
+void *display_get_frame_addr(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return &drv->framebuf[0];
+}
+
+void display_refresh(void) { display_sync_with_fb(); }
+
+const char *display_save(const char *prefix) { return NULL; }
+
+void display_clear_save(void) {}
+
+void display_set_compatible_settings() {}
+
+// Functions for drawing on display
+/*
+
+// Fills a rectangle with a specified color
+void display_fill(gdc_dma2d_t *dp);
+
+// Copies an RGB565 bitmap to specified rectangle
+void display_copy_rgb565(gdc_dma2d_t *dp);
+
+// Copies a MONO4 bitmap to specified rectangle
+void display_copy_mono4(gdc_dma2d_t *dp);
+
+// Copies a MONO1P bitmap to specified rectangle
+void display_copy_mono1p(gdc_dma2d_t *dp);
+*/
diff --git a/core/embed/trezorhal/stm32f4/display/vg-2864/display_driver.c b/core/embed/trezorhal/stm32f4/display/vg-2864/display_driver.c
new file mode 100644
index 000000000..9e6f1fb3e
--- /dev/null
+++ b/core/embed/trezorhal/stm32f4/display/vg-2864/display_driver.c
@@ -0,0 +1,351 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "xdisplay.h"
+
+#ifdef USE_CONSUMPTION_MASK
+#include "consumption_mask.h"
+#endif
+
+#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 64)
+#error "Incompatible display resolution"
+#endif
+
+// This file implements display driver for monochromatic display V-2864KSWEG01
+// with 128x64 resolution connected to CPU via SPI interface.
+//
+// This type of display is used with T3T1 model (Trezor TS3)
+
+// Display driver context.
+typedef struct {
+ // SPI driver instance
+ SPI_HandleTypeDef spi;
+ // Frame buffer (8-bit Mono)
+ uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY];
+ // Current display orientation (0 or 180)
+ int orientation_angle;
+ // Current backlight level ranging from 0 to 255
+ int backlight_level;
+} display_driver_t;
+
+// Display driver instance
+static display_driver_t g_display_driver;
+
+// Display controller registers
+#define OLED_SETCONTRAST 0x81
+#define OLED_DISPLAYALLON_RESUME 0xA4
+#define OLED_DISPLAYALLON 0xA5
+#define OLED_NORMALDISPLAY 0xA6
+#define OLED_INVERTDISPLAY 0xA7
+#define OLED_DISPLAYOFF 0xAE
+#define OLED_DISPLAYON 0xAF
+#define OLED_SETDISPLAYOFFSET 0xD3
+#define OLED_SETCOMPINS 0xDA
+#define OLED_SETVCOMDETECT 0xDB
+#define OLED_SETDISPLAYCLOCKDIV 0xD5
+#define OLED_SETPRECHARGE 0xD9
+#define OLED_SETMULTIPLEX 0xA8
+#define OLED_SETLOWCOLUMN 0x00
+#define OLED_SETHIGHCOLUMN 0x10
+#define OLED_SETSTARTLINE 0x40
+#define OLED_MEMORYMODE 0x20
+#define OLED_COMSCANINC 0xC0
+#define OLED_COMSCANDEC 0xC8
+#define OLED_SEGREMAP 0xA0
+#define OLED_CHARGEPUMP 0x8D
+
+// Display controller initialization sequence
+static const uint8_t vg_2864ksweg01_init_seq[] = {OLED_DISPLAYOFF,
+ OLED_SETDISPLAYCLOCKDIV,
+ 0x80,
+ OLED_SETMULTIPLEX,
+ 0x3F, // 128x64
+ OLED_SETDISPLAYOFFSET,
+ 0x00,
+ OLED_SETSTARTLINE | 0x00,
+ OLED_CHARGEPUMP,
+ 0x14,
+ OLED_MEMORYMODE,
+ 0x00,
+ OLED_SEGREMAP | 0x01,
+ OLED_COMSCANDEC,
+ OLED_SETCOMPINS,
+ 0x12, // 128x64
+ OLED_SETCONTRAST,
+ 0xCF,
+ OLED_SETPRECHARGE,
+ 0xF1,
+ OLED_SETVCOMDETECT,
+ 0x40,
+ OLED_DISPLAYALLON_RESUME,
+ OLED_NORMALDISPLAY,
+ OLED_DISPLAYON};
+
+// Configures SPI driver/controller
+static bool display_init_spi(display_driver_t *drv) {
+ drv->spi.Instance = OLED_SPI;
+ drv->spi.State = HAL_SPI_STATE_RESET;
+ drv->spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
+ drv->spi.Init.Direction = SPI_DIRECTION_2LINES;
+ drv->spi.Init.CLKPhase = SPI_PHASE_1EDGE;
+ drv->spi.Init.CLKPolarity = SPI_POLARITY_LOW;
+ drv->spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
+ drv->spi.Init.CRCPolynomial = 7;
+ drv->spi.Init.DataSize = SPI_DATASIZE_8BIT;
+ drv->spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
+ drv->spi.Init.NSS = SPI_NSS_HARD_OUTPUT;
+ drv->spi.Init.TIMode = SPI_TIMODE_DISABLE;
+ drv->spi.Init.Mode = SPI_MODE_MASTER;
+
+ return (HAL_OK == HAL_SPI_Init(&drv->spi)) ? true : false;
+}
+
+// Sends specified number of bytes to the display via SPI interface
+static void display_send_bytes(display_driver_t *drv, const uint8_t *data,
+ size_t len) {
+ volatile int32_t timeout = 1000; // !@# why???
+ for (int i = 0; i < timeout; i++)
+ ;
+
+ if (HAL_OK != HAL_SPI_Transmit(&drv->spi, (uint8_t *)data, len, 1000)) {
+ // TODO: error
+ return;
+ }
+ while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) {
+ }
+}
+
+#define COLLECT_ROW_BYTE(src) \
+ (0 | (*(src + (0 * DISPLAY_RESX)) ? 128 : 0) | \
+ (*(src + (1 * DISPLAY_RESX)) ? 64 : 0) | \
+ (*(src + (2 * DISPLAY_RESX)) ? 32 : 0) | \
+ (*(src + (3 * DISPLAY_RESX)) ? 16 : 0) | \
+ (*(src + (4 * DISPLAY_RESX)) ? 8 : 0) | \
+ (*(src + (5 * DISPLAY_RESX)) ? 4 : 0) | \
+ (*(src + (6 * DISPLAY_RESX)) ? 2 : 0) | \
+ (*(src + (7 * DISPLAY_RESX)) ? 1 : 0))
+
+// Copies the framebuffer to the display via SPI interface
+static void display_sync_with_fb(display_driver_t *drv) {
+ static const uint8_t cursor_set_seq[3] = {OLED_SETLOWCOLUMN | 0x00,
+ OLED_SETHIGHCOLUMN | 0x00,
+ OLED_SETSTARTLINE | 0x00};
+
+ // SPI select
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
+ // Set the cursor to the screen top-left corner
+ display_send_bytes(drv, &cursor_set_seq[0], sizeof(cursor_set_seq));
+
+ // SPI deselect
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
+ // Set to DATA
+ HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_SET);
+ // SPI select
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
+
+ // Send whole framebuffer to the display
+ for (int y = 0; y < DISPLAY_RESY / 8; y++) {
+ uint8_t buff[DISPLAY_RESX];
+ uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8];
+
+ if (drv->orientation_angle == 0) {
+ for (int x = 0; x < DISPLAY_RESX; x++) {
+ buff[x] = COLLECT_ROW_BYTE(src);
+ src++;
+ }
+ } else {
+ for (int x = DISPLAY_RESX - 1; x >= 0; x--) {
+ buff[x] = COLLECT_ROW_BYTE(src);
+ src++;
+ }
+ }
+
+ if (HAL_OK != HAL_SPI_Transmit(&drv->spi, &buff[0], sizeof(buff), 1000)) {
+ // TODO: error
+ return;
+ }
+ }
+
+ while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) {
+ }
+
+ // SPI deselect
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
+ // Set to CMD
+ HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
+}
+
+void display_init(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ memset(drv, 0, sizeof(display_driver_t));
+ drv->backlight_level = 255;
+
+ OLED_DC_CLK_ENA();
+ OLED_CS_CLK_ENA();
+ OLED_RST_CLK_ENA();
+ OLED_SPI_SCK_CLK_ENA();
+ OLED_SPI_MOSI_CLK_ENA();
+ OLED_SPI_CLK_ENA();
+
+ GPIO_InitTypeDef GPIO_InitStructure;
+
+ // Set GPIO for OLED display
+ GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStructure.Alternate = 0;
+ GPIO_InitStructure.Pin = OLED_CS_PIN;
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
+ HAL_GPIO_Init(OLED_CS_PORT, &GPIO_InitStructure);
+ GPIO_InitStructure.Pin = OLED_DC_PIN;
+ HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
+ HAL_GPIO_Init(OLED_DC_PORT, &GPIO_InitStructure);
+ GPIO_InitStructure.Pin = OLED_RST_PIN;
+ HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
+ HAL_GPIO_Init(OLED_RST_PORT, &GPIO_InitStructure);
+
+ // Enable SPI 1 for OLED display
+ GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
+ GPIO_InitStructure.Pull = GPIO_NOPULL;
+ GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+ GPIO_InitStructure.Alternate = OLED_SPI_AF;
+ GPIO_InitStructure.Pin = OLED_SPI_SCK_PIN;
+ HAL_GPIO_Init(OLED_SPI_SCK_PORT, &GPIO_InitStructure);
+ GPIO_InitStructure.Pin = OLED_SPI_MOSI_PIN;
+ HAL_GPIO_Init(OLED_SPI_MOSI_PORT, &GPIO_InitStructure);
+
+ // Initialize SPI controller
+ display_init_spi(drv);
+
+ // Set to CMD
+ HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
+ // SPI deselect
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
+
+ // Reset the LCD
+ HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
+ HAL_Delay(1);
+ HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
+ HAL_Delay(1);
+ HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
+
+ // SPI select
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
+ // Send initialization command sequence
+ display_send_bytes(drv, &vg_2864ksweg01_init_seq[0],
+ sizeof(vg_2864ksweg01_init_seq));
+ // SPI deselect
+ HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
+
+ // Clear display internal framebuffer
+ display_sync_with_fb(drv);
+}
+
+void display_reinit(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ memset(drv, 0, sizeof(display_driver_t));
+ drv->backlight_level = 255;
+
+ display_init_spi(drv);
+}
+
+void display_finish_actions(void) {
+ /// Not used and intentionally left empty
+}
+
+int display_set_backlight(int level) {
+ display_driver_t *drv = &g_display_driver;
+
+ drv->backlight_level = 255;
+ return drv->backlight_level;
+}
+
+int display_get_backlight(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return drv->backlight_level;
+}
+
+int display_set_orientation(int angle) {
+ display_driver_t *drv = &g_display_driver;
+
+ if (angle != drv->orientation_angle) {
+ if (angle == 0 || angle == 180) {
+ drv->orientation_angle = angle;
+ display_sync_with_fb(drv);
+ }
+ }
+
+ return drv->orientation_angle;
+}
+
+int display_get_orientation(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return drv->orientation_angle;
+}
+
+void *display_get_frame_addr(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ return &drv->framebuf[0];
+}
+
+void display_refresh(void) {
+ display_driver_t *drv = &g_display_driver;
+
+#if defined USE_CONSUMPTION_MASK && !defined BOARDLOADER
+ // This is an intentional randomization of the consumption masking algorithm
+ // after every change on the display
+ consumption_mask_randomize();
+#endif
+
+ // Sends the current frame buffer to the display
+ display_sync_with_fb(drv);
+}
+
+const char *display_save(const char *prefix) { return NULL; }
+
+void display_clear_save(void) {}
+
+void display_set_compatible_settings() {}
+
+/*
+
+// Fills a rectangle with a specified color
+void display_fill(dma2d_params_t *dp) {
+
+}
+
+// Copies a MONO1P bitmap to specified rectangle
+void display_copy_mono1p(dma2d_params_t *dp) {
+
+}
+
+*/
diff --git a/core/embed/trezorhal/stm32f4/displays/ltdc.c b/core/embed/trezorhal/stm32f4/displays/ltdc.c
index 0024773ed..66cb7663d 100644
--- a/core/embed/trezorhal/stm32f4/displays/ltdc.c
+++ b/core/embed/trezorhal/stm32f4/displays/ltdc.c
@@ -46,12 +46,12 @@ uint8_t *const DISPLAY_DATA_ADDRESS = 0;
uint16_t cursor_x = 0;
uint16_t cursor_y = 0;
uint16_t window_x0 = 0;
-uint16_t window_y0 = MAX_DISPLAY_RESX - 1;
+uint16_t window_y0 = DISPLAY_RESX - 1;
uint16_t window_x1 = 0;
-uint16_t window_y1 = MAX_DISPLAY_RESY - 1;
+uint16_t window_y1 = DISPLAY_RESY - 1;
void display_pixeldata(uint16_t c) {
- ((uint16_t *)LCD_FRAME_BUFFER)[(cursor_y * MAX_DISPLAY_RESX) + cursor_x] = c;
+ ((uint16_t *)LCD_FRAME_BUFFER)[(cursor_y * DISPLAY_RESX) + cursor_x] = c;
cursor_x++;
@@ -83,9 +83,9 @@ void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
/* Layer Init */
Layercfg.WindowX0 = 0;
- Layercfg.WindowX1 = MAX_DISPLAY_RESX;
+ Layercfg.WindowX1 = DISPLAY_RESX;
Layercfg.WindowY0 = 0;
- Layercfg.WindowY1 = MAX_DISPLAY_RESY;
+ Layercfg.WindowY1 = DISPLAY_RESY;
Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
Layercfg.FBStartAdress = FB_Address;
Layercfg.Alpha = 255;
@@ -95,8 +95,8 @@ void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
Layercfg.Backcolor.Red = 0;
Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
- Layercfg.ImageWidth = MAX_DISPLAY_RESX;
- Layercfg.ImageHeight = MAX_DISPLAY_RESY;
+ Layercfg.ImageWidth = DISPLAY_RESX;
+ Layercfg.ImageHeight = DISPLAY_RESY;
HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex);
@@ -380,7 +380,7 @@ void display_efficient_clear(void) {
uint8_t *display_get_wr_addr(void) {
uint32_t address = LCD_FRAME_BUFFER;
/* Get the rectangle start address */
- address = (address + (2 * ((cursor_y)*MAX_DISPLAY_RESX + (cursor_x))));
+ address = (address + (2 * ((cursor_y)*DISPLAY_RESX + (cursor_x))));
return (uint8_t *)address;
}
@@ -413,7 +413,7 @@ void display_shift_window(uint16_t pixels) {
}
uint16_t display_get_window_offset(void) {
- return MAX_DISPLAY_RESX - display_get_window_width();
+ return DISPLAY_RESX - display_get_window_width();
}
void display_finish_actions(void) {}
diff --git a/core/embed/trezorhal/stm32f4/displays/ltdc.h b/core/embed/trezorhal/stm32f4/displays/ltdc.h
index 2efb2be96..94d83a026 100644
--- a/core/embed/trezorhal/stm32f4/displays/ltdc.h
+++ b/core/embed/trezorhal/stm32f4/displays/ltdc.h
@@ -5,8 +5,8 @@
#include STM32_HAL_H
#define TREZOR_FONT_BPP 4
-#define DISPLAY_FRAMEBUFFER_WIDTH MAX_DISPLAY_RESX
-#define DISPLAY_FRAMEBUFFER_HEIGHT MAX_DISPLAY_RESY
+#define DISPLAY_FRAMEBUFFER_WIDTH DISPLAY_RESX
+#define DISPLAY_FRAMEBUFFER_HEIGHT DISPLAY_RESY
#define DISPLAY_FRAMEBUFFER_OFFSET_X 0
#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
diff --git a/core/embed/trezorhal/stm32f4/displays/st7789v.c b/core/embed/trezorhal/stm32f4/displays/st7789v.c
index 2d1a6e798..7e284da26 100644
--- a/core/embed/trezorhal/stm32f4/displays/st7789v.c
+++ b/core/embed/trezorhal/stm32f4/displays/st7789v.c
@@ -34,6 +34,8 @@
#include "displays/panels/lx154a2411.h"
#include "displays/panels/lx154a2422.h"
#include "displays/panels/tf15411a.h"
+#else
+#include "displays/panels/lx154a2422.h"
#endif
// using const volatile instead of #define results in binaries that change
@@ -241,7 +243,7 @@ int display_orientation(int degrees) {
lx154a2422_rotate(degrees, &DISPLAY_PADDING);
}
#else
- DISPLAY_PANEL_ROTATE(degrees, &DISPLAY_PADDING);
+ lx154a2422_rotate(degrees, &DISPLAY_PADDING);
#endif
panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
}
@@ -292,7 +294,7 @@ void display_init_seq(void) {
_154a_init_seq();
}
#else
- DISPLAY_PANEL_INIT_SEQ();
+ lx154a2422_init_seq();
#endif
display_unsleep();
diff --git a/core/embed/trezorhal/stm32f4/dma2d_gdc.c b/core/embed/trezorhal/stm32f4/dma2d_gl.c
similarity index 81%
rename from core/embed/trezorhal/stm32f4/dma2d_gdc.c
rename to core/embed/trezorhal/stm32f4/dma2d_gl.c
index c3a643db9..5c98fc9d6 100644
--- a/core/embed/trezorhal/stm32f4/dma2d_gdc.c
+++ b/core/embed/trezorhal/stm32f4/dma2d_gl.c
@@ -20,9 +20,9 @@
#include STM32_HAL_H
#include
-#include "dma2d.h"
-#include "../gdc/gdc_color.h"
+#include "gl_color.h"
+#include "gl_dma2d.h"
static DMA2D_HandleTypeDef dma2d_handle = {
.Instance = (DMA2D_TypeDef*)DMA2D_BASE,
@@ -50,9 +50,22 @@ bool dma2d_rgb565_fill(const dma2d_params_t* dp) {
dp->dst_stride / sizeof(uint16_t) - dp->width;
HAL_DMA2D_Init(&dma2d_handle);
- HAL_DMA2D_Start(&dma2d_handle, gdc_color_to_color32(dp->src_fg),
+ HAL_DMA2D_Start(&dma2d_handle, gl_color_to_color32(dp->src_fg),
(uint32_t)dp->dst_row + dp->dst_x * sizeof(uint16_t),
dp->width, dp->height);
+ /*
+
+ MODIFY_REG(dma2d_handle.Instance->CR, DMA2D_CR_MODE, DMA2D_R2M);
+ MODIFY_REG(dma2d_handle.Instance->OPFCCR, DMA2D_OPFCCR_CM,
+ DMA2D_OUTPUT_RGB565); MODIFY_REG(dma2d_handle.Instance->OOR,
+ DMA2D_OOR_LO, dp->dst_stride / sizeof(uint16_t) - dp->width);
+ MODIFY_REG(dma2d_handle.Instance->NLR, (DMA2D_NLR_NL|DMA2D_NLR_PL),
+ (dp->height| (dp->width << 16))); WRITE_REG(dma2d_handle.Instance->OMAR,
+ (uint32_t)dp->dst_row + dp->dst_x * sizeof(uint16_t));
+ WRITE_REG(dma2d_handle.Instance->OCOLR,
+ gl_color_to_color32(dp->src_fg));
+ ((dma2d_handle).Instance->CR |= DMA2D_CR_START);
+ */
} else {
// STM32F4 can not accelerate blending with the fixed color
uint16_t* dst_ptr = (uint16_t*)dp->dst_row + dp->dst_x;
@@ -60,7 +73,7 @@ bool dma2d_rgb565_fill(const dma2d_params_t* dp) {
uint8_t alpha = dp->src_alpha;
while (height-- > 0) {
for (int x = 0; x < dp->width; x++) {
- dst_ptr[x] = gdc_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha);
+ dst_ptr[x] = gl_color16_blend_a8(dp->src_fg, dst_ptr[x], alpha);
}
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
}
@@ -70,27 +83,27 @@ bool dma2d_rgb565_fill(const dma2d_params_t* dp) {
}
/*
-static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) {
+static void dma2d_config_clut(uint32_t layer, gl_color_t fg, gl_color_t bg) {
#define LAYER_COUNT 2
#define GRADIENT_STEPS 16
static struct {
- gdc_color32_t gradient[GRADIENT_STEPS];
+ gl_color32_t gradient[GRADIENT_STEPS];
} cache[LAYER_COUNT] = { 0 };
if (layer >= LAYER_COUNT) {
return;
}
- uint32_t c_fg = gdc_color_to_color32(fg);
- uint32_t c_bg = gdc_color_to_color32(bg);
+ uint32_t c_fg = gl_color_to_color32(fg);
+ uint32_t c_bg = gl_color_to_color32(bg);
uint32_t* gradient = cache[layer].gradient;
if (c_bg != gradient[0] || c_fg != gradient[GRADIENT_STEPS - 1]) {
for (int step = 0; step < GRADIENT_STEPS; step++) {
- gradient[step] = gdc_color32_blend_a4(fg, bg, step);
+ gradient[step] = gl_color32_blend_a4(fg, bg, step);
}
DMA2D_CLUTCfgTypeDef clut;
@@ -105,13 +118,13 @@ static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) {
}
}*/
-static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) {
+static void dma2d_config_clut(uint32_t layer, gl_color_t fg, gl_color_t bg) {
#define LAYER_COUNT 2
#define GRADIENT_STEPS 16
static struct {
- gdc_color_t c_fg;
- gdc_color_t c_bg;
+ gl_color_t c_fg;
+ gl_color_t c_bg;
} cache[LAYER_COUNT] = {0};
if (layer >= LAYER_COUNT) {
@@ -126,7 +139,7 @@ static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) {
cache[layer].c_bg = bg;
for (int step = 0; step < GRADIENT_STEPS; step++) {
- clut[step] = gdc_color32_blend_a4(fg, bg, step);
+ clut[step] = gl_color32_blend_a4(fg, bg, step);
}
DMA2D_CLUTCfgTypeDef clut;
@@ -139,7 +152,7 @@ static void dma2d_config_clut(uint32_t layer, gdc_color_t fg, gdc_color_t bg) {
}
static void dma2d_rgb565_copy_mono4_first_col(dma2d_params_t* dp,
- const gdc_color16_t* gradient) {
+ const gl_color16_t* gradient) {
uint16_t* dst_ptr = (uint16_t*)dp->dst_row + dp->dst_x;
uint8_t* src_ptr = (uint8_t*)dp->src_row + dp->src_x / 2;
@@ -154,7 +167,7 @@ static void dma2d_rgb565_copy_mono4_first_col(dma2d_params_t* dp,
}
static void dma2d_rgb565_copy_mono4_last_col(dma2d_params_t* dp,
- const gdc_color16_t* gradient) {
+ const gl_color16_t* gradient) {
uint16_t* dst_ptr = (uint16_t*)dp->dst_row + (dp->dst_x + dp->width - 1);
uint8_t* src_ptr = (uint8_t*)dp->src_row + (dp->src_x + dp->width - 1) / 2;
@@ -169,7 +182,7 @@ static void dma2d_rgb565_copy_mono4_last_col(dma2d_params_t* dp,
}
bool dma2d_rgb565_copy_mono4(const dma2d_params_t* params) {
- const gdc_color16_t* src_gradient = NULL;
+ const gl_color16_t* src_gradient = NULL;
dma2d_params_t dp_copy = *params;
dma2d_params_t* dp = &dp_copy;
@@ -179,7 +192,7 @@ bool dma2d_rgb565_copy_mono4(const dma2d_params_t* params) {
if (dp->src_x & 1) {
// First column of mono4 bitmap is odd
// Use the CPU to draw the first column
- src_gradient = gdc_color16_gradient_a4(dp->src_fg, dp->src_bg);
+ src_gradient = gl_color16_gradient_a4(dp->src_fg, dp->src_bg);
dma2d_rgb565_copy_mono4_first_col(dp, src_gradient);
dp->dst_x += 1;
dp->src_x += 1;
@@ -190,7 +203,7 @@ bool dma2d_rgb565_copy_mono4(const dma2d_params_t* params) {
// The width is odd
// Use the CPU to draw the last column
if (src_gradient == NULL) {
- src_gradient = gdc_color16_gradient_a4(dp->src_fg, dp->src_bg);
+ src_gradient = gl_color16_gradient_a4(dp->src_fg, dp->src_bg);
}
dma2d_rgb565_copy_mono4_last_col(dp, src_gradient);
dp->width -= 1;
@@ -249,8 +262,8 @@ static void dma2d_rgb565_blend_mono4_first_col(const dma2d_params_t* dp) {
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] >> 4;
- dst_ptr[0] = gdc_color16_blend_a4(
- dp->src_fg, gdc_color16_to_color(dst_ptr[0]), fg_alpha);
+ dst_ptr[0] = gl_color16_blend_a4(dp->src_fg,
+ gl_color16_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
@@ -264,8 +277,8 @@ static void dma2d_rgb565_blend_mono4_last_col(const dma2d_params_t* dp) {
while (height-- > 0) {
uint8_t fg_alpha = src_ptr[0] & 0x0F;
- dst_ptr[0] = gdc_color16_blend_a4(
- dp->src_fg, gdc_color16_to_color(dst_ptr[0]), fg_alpha);
+ dst_ptr[0] = gl_color16_blend_a4(dp->src_fg,
+ gl_color16_to_color(dst_ptr[0]), fg_alpha);
dst_ptr += dp->dst_stride / sizeof(*dst_ptr);
src_ptr += dp->src_stride / sizeof(*src_ptr);
}
@@ -303,7 +316,7 @@ bool dma2d_rgb565_blend_mono4(const dma2d_params_t* params) {
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
dma2d_handle.LayerCfg[1].InputOffset = dp->src_stride * 2 - dp->width;
dma2d_handle.LayerCfg[1].AlphaMode = 0;
- dma2d_handle.LayerCfg[1].InputAlpha = gdc_color_to_color32(dp->src_fg);
+ dma2d_handle.LayerCfg[1].InputAlpha = gl_color_to_color32(dp->src_fg);
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
diff --git a/core/embed/trezorhal/stm32f4/touch/ft6x36.c b/core/embed/trezorhal/stm32f4/touch/ft6x36.c
index e2729541c..e1bb494fb 100644
--- a/core/embed/trezorhal/stm32f4/touch/ft6x36.c
+++ b/core/embed/trezorhal/stm32f4/touch/ft6x36.c
@@ -260,8 +260,8 @@ uint32_t touch_read(void) {
// first touch) (tested with FT6206)
const uint32_t event_flag = touch_data[3] & 0xC0;
if (touch_data[1] == GESTURE_NO_GESTURE) {
- xy = TRANSFORM_TOUCH_COORDS((X_POS_MSB << 8) | X_POS_LSB,
- (Y_POS_MSB << 8) | Y_POS_LSB);
+ xy = touch_pack_xy((X_POS_MSB << 8) | X_POS_LSB,
+ (Y_POS_MSB << 8) | Y_POS_LSB);
if ((number_of_touch_points == 1) && (event_flag == EVENT_PRESS_DOWN)) {
touching = 1;
return TOUCH_START | xy;
diff --git a/core/embed/trezorhal/stm32u5/display/st-7789 b/core/embed/trezorhal/stm32u5/display/st-7789
new file mode 120000
index 000000000..3ad01c673
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/display/st-7789
@@ -0,0 +1 @@
+../../stm32f4/display/st-7789
\ No newline at end of file
diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c
new file mode 100644
index 000000000..97eba660b
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c
@@ -0,0 +1,135 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "display_internal.h"
+#include "xdisplay.h"
+
+#if (DISPLAY_RESX != 480) || (DISPLAY_RESY != 480)
+#error "Incompatible display resolution"
+#endif
+
+// Display driver context.
+typedef struct {
+ // Current display orientation (0, 90, 180, 270)
+ int orientation_angle;
+ // Current backlight level ranging from 0 to 255
+ int backlight_level;
+} display_driver_t;
+
+// Display driver instance
+static display_driver_t g_display_driver;
+
+void display_init(void) {
+ RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
+
+ // Initializes the common periph clock
+ PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_DSI;
+ PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3;
+ PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3;
+ PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
+ PeriphClkInit.PLL3.PLL3M = 4;
+ PeriphClkInit.PLL3.PLL3N = 125;
+ PeriphClkInit.PLL3.PLL3P = 8;
+ PeriphClkInit.PLL3.PLL3Q = 2;
+ PeriphClkInit.PLL3.PLL3R = 24;
+ PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0;
+ PeriphClkInit.PLL3.PLL3FRACN = 0;
+ PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP | RCC_PLL3_DIVR;
+ HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
+
+ // Clear framebuffers
+ memset(physical_frame_buffer_0, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
+ memset(physical_frame_buffer_1, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
+
+ BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT);
+ BSP_LCD_SetBrightness(0, 100);
+ BSP_LCD_DisplayOn(0);
+}
+
+void display_reinit(void) {
+ BSP_LCD_Reinit(0);
+ if (current_frame_buffer == 0) {
+ BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
+ } else {
+ BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
+ }
+}
+
+void display_finish_actions(void) {
+ // Not used and intentionally left empty
+}
+
+int display_set_backlight(int level) {
+ display_driver_t* drv = &g_display_driver;
+
+ // Just emulation, not doing anything
+ drv->backlight_level = level;
+ return level;
+}
+
+int display_get_backlight(void) {
+ display_driver_t* drv = &g_display_driver;
+
+ return drv->orientation_angle;
+}
+
+int display_set_orientation(int angle) {
+ display_driver_t* drv = &g_display_driver;
+
+ if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
+ // Just emulation, not doing anything
+ drv->orientation_angle = angle;
+ }
+
+ return drv->orientation_angle;
+}
+
+int display_get_orientation(void) {
+ display_driver_t* drv = &g_display_driver;
+
+ return drv->orientation_angle;
+}
+
+const char* display_save(const char* prefix) { return NULL; }
+
+void display_clear_save(void) {}
+
+void display_set_compatible_settings() {}
+
+// Functions for drawing on display
+/*
+
+// Fills a rectangle with a specified color
+void display_fill(gdc_dma2d_t *dp);
+
+// Copies an RGB565 bitmap to specified rectangle
+void display_copy_rgb565(gdc_dma2d_t *dp);
+
+// Copies a MONO4 bitmap to specified rectangle
+void display_copy_mono4(gdc_dma2d_t *dp);
+
+// Copies a MONO1P bitmap to specified rectangle
+void display_copy_mono1p(gdc_dma2d_t *dp);
+*/
diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c
new file mode 100644
index 000000000..741f48fe5
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "display_internal.h"
+
+// Physical frame buffers in internal SRAM memory
+__attribute__((section(".fb1")))
+ALIGN_32BYTES(uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
+
+__attribute__((section(".fb2")))
+ALIGN_32BYTES(uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
+
+// The current frame buffer selector at fixed memory address
+// It's shared between bootloaders and the firmware
+__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
+ 0;
+
+void* display_get_frame_addr(void) {
+ if (current_frame_buffer == 0) {
+ return (void*)GFXMMU_VIRTUAL_BUFFER0_BASE_S;
+ } else {
+ return (void*)GFXMMU_VIRTUAL_BUFFER1_BASE_S;
+ }
+}
+
+void display_refresh(void) {
+ current_frame_buffer = current_frame_buffer ? 0 : 1;
+
+ if (current_frame_buffer == 0) {
+ BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
+ memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
+ PHYSICAL_FRAME_BUFFER_SIZE);
+ } else {
+ BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
+ memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
+ PHYSICAL_FRAME_BUFFER_SIZE);
+ }
+}
\ No newline at end of file
diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_gfxmmu_lut.h b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_gfxmmu_lut.h
new file mode 100644
index 000000000..86528b9d9
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_gfxmmu_lut.h
@@ -0,0 +1,1006 @@
+/* USER CODE BEGIN Header */
+/**
+ ******************************************************************************
+ * File Name : gfxmmu_lut.h
+ * Description : header file for GFX MMU Configuration Table
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2022 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+/* USER CODE END Header */
+/* Define to prevent recursive inclusion -------------------------------------*/
+#ifndef __gfxmmu_lut_H
+#define __gfxmmu_lut_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+// GFX MMU Configuration Table
+
+#define GFXMMU_FB_SIZE 733936
+#define GFXMMU_LUT_FIRST 0
+#define GFXMMU_LUT_LAST 479
+#define GFXMMU_LUT_SIZE 480
+
+uint32_t gfxmmu_lut[2 * GFXMMU_LUT_SIZE] = {
+ 0x00413601, // GFXMMU_LUT0L
+ 0x003FFCA0, // GFXMMU_LUT0H
+ 0x00433401, // GFXMMU_LUT1L
+ 0x003FFD80, // GFXMMU_LUT1H
+ 0x00453201, // GFXMMU_LUT2L
+ 0x003FFEA0, // GFXMMU_LUT2H
+ 0x00463101, // GFXMMU_LUT3L
+ 0x003FFFF0, // GFXMMU_LUT3H
+ 0x00482F01, // GFXMMU_LUT4L
+ 0x00000170, // GFXMMU_LUT4H
+ 0x00492E01, // GFXMMU_LUT5L
+ 0x00000320, // GFXMMU_LUT5H
+ 0x004A2D01, // GFXMMU_LUT6L
+ 0x000004F0, // GFXMMU_LUT6H
+ 0x004B2C01, // GFXMMU_LUT7L
+ 0x000006E0, // GFXMMU_LUT7H
+ 0x004C2B01, // GFXMMU_LUT8L
+ 0x000008F0, // GFXMMU_LUT8H
+ 0x004D2A01, // GFXMMU_LUT9L
+ 0x00000B20, // GFXMMU_LUT9H
+ 0x004D2A01, // GFXMMU_LUT10L
+ 0x00000D60, // GFXMMU_LUT10H
+ 0x004E2901, // GFXMMU_LUT11L
+ 0x00000FB0, // GFXMMU_LUT11H
+ 0x004F2801, // GFXMMU_LUT12L
+ 0x00001220, // GFXMMU_LUT12H
+ 0x00502701, // GFXMMU_LUT13L
+ 0x000014B0, // GFXMMU_LUT13H
+ 0x00502701, // GFXMMU_LUT14L
+ 0x00001750, // GFXMMU_LUT14H
+ 0x00512601, // GFXMMU_LUT15L
+ 0x00001A00, // GFXMMU_LUT15H
+ 0x00522501, // GFXMMU_LUT16L
+ 0x00001CD0, // GFXMMU_LUT16H
+ 0x00522501, // GFXMMU_LUT17L
+ 0x00001FB0, // GFXMMU_LUT17H
+ 0x00532401, // GFXMMU_LUT18L
+ 0x000022A0, // GFXMMU_LUT18H
+ 0x00532401, // GFXMMU_LUT19L
+ 0x000025A0, // GFXMMU_LUT19H
+ 0x00542301, // GFXMMU_LUT20L
+ 0x000028B0, // GFXMMU_LUT20H
+ 0x00552201, // GFXMMU_LUT21L
+ 0x00002BE0, // GFXMMU_LUT21H
+ 0x00552201, // GFXMMU_LUT22L
+ 0x00002F20, // GFXMMU_LUT22H
+ 0x00562101, // GFXMMU_LUT23L
+ 0x00003270, // GFXMMU_LUT23H
+ 0x00562101, // GFXMMU_LUT24L
+ 0x000035D0, // GFXMMU_LUT24H
+ 0x00572001, // GFXMMU_LUT25L
+ 0x00003940, // GFXMMU_LUT25H
+ 0x00572001, // GFXMMU_LUT26L
+ 0x00003CC0, // GFXMMU_LUT26H
+ 0x00581F01, // GFXMMU_LUT27L
+ 0x00004050, // GFXMMU_LUT27H
+ 0x00581F01, // GFXMMU_LUT28L
+ 0x000043F0, // GFXMMU_LUT28H
+ 0x00591E01, // GFXMMU_LUT29L
+ 0x000047A0, // GFXMMU_LUT29H
+ 0x00591E01, // GFXMMU_LUT30L
+ 0x00004B60, // GFXMMU_LUT30H
+ 0x00591E01, // GFXMMU_LUT31L
+ 0x00004F20, // GFXMMU_LUT31H
+ 0x005A1D01, // GFXMMU_LUT32L
+ 0x000052F0, // GFXMMU_LUT32H
+ 0x005A1D01, // GFXMMU_LUT33L
+ 0x000056D0, // GFXMMU_LUT33H
+ 0x005B1C01, // GFXMMU_LUT34L
+ 0x00005AC0, // GFXMMU_LUT34H
+ 0x005B1C01, // GFXMMU_LUT35L
+ 0x00005EC0, // GFXMMU_LUT35H
+ 0x005C1B01, // GFXMMU_LUT36L
+ 0x000062D0, // GFXMMU_LUT36H
+ 0x005C1B01, // GFXMMU_LUT37L
+ 0x000066F0, // GFXMMU_LUT37H
+ 0x005C1B01, // GFXMMU_LUT38L
+ 0x00006B10, // GFXMMU_LUT38H
+ 0x005D1A01, // GFXMMU_LUT39L
+ 0x00006F40, // GFXMMU_LUT39H
+ 0x005D1A01, // GFXMMU_LUT40L
+ 0x00007380, // GFXMMU_LUT40H
+ 0x005D1A01, // GFXMMU_LUT41L
+ 0x000077C0, // GFXMMU_LUT41H
+ 0x005E1901, // GFXMMU_LUT42L
+ 0x00007C10, // GFXMMU_LUT42H
+ 0x005E1901, // GFXMMU_LUT43L
+ 0x00008070, // GFXMMU_LUT43H
+ 0x005E1901, // GFXMMU_LUT44L
+ 0x000084D0, // GFXMMU_LUT44H
+ 0x005F1801, // GFXMMU_LUT45L
+ 0x00008940, // GFXMMU_LUT45H
+ 0x005F1801, // GFXMMU_LUT46L
+ 0x00008DC0, // GFXMMU_LUT46H
+ 0x00601801, // GFXMMU_LUT47L
+ 0x00009240, // GFXMMU_LUT47H
+ 0x00601701, // GFXMMU_LUT48L
+ 0x000096E0, // GFXMMU_LUT48H
+ 0x00601701, // GFXMMU_LUT49L
+ 0x00009B80, // GFXMMU_LUT49H
+ 0x00601701, // GFXMMU_LUT50L
+ 0x0000A020, // GFXMMU_LUT50H
+ 0x00611601, // GFXMMU_LUT51L
+ 0x0000A4D0, // GFXMMU_LUT51H
+ 0x00611601, // GFXMMU_LUT52L
+ 0x0000A990, // GFXMMU_LUT52H
+ 0x00611601, // GFXMMU_LUT53L
+ 0x0000AE50, // GFXMMU_LUT53H
+ 0x00621501, // GFXMMU_LUT54L
+ 0x0000B320, // GFXMMU_LUT54H
+ 0x00621501, // GFXMMU_LUT55L
+ 0x0000B800, // GFXMMU_LUT55H
+ 0x00621501, // GFXMMU_LUT56L
+ 0x0000BCE0, // GFXMMU_LUT56H
+ 0x00631401, // GFXMMU_LUT57L
+ 0x0000C1D0, // GFXMMU_LUT57H
+ 0x00631401, // GFXMMU_LUT58L
+ 0x0000C6D0, // GFXMMU_LUT58H
+ 0x00631401, // GFXMMU_LUT59L
+ 0x0000CBD0, // GFXMMU_LUT59H
+ 0x00631401, // GFXMMU_LUT60L
+ 0x0000D0D0, // GFXMMU_LUT60H
+ 0x00641301, // GFXMMU_LUT61L
+ 0x0000D5E0, // GFXMMU_LUT61H
+ 0x00641301, // GFXMMU_LUT62L
+ 0x0000DB00, // GFXMMU_LUT62H
+ 0x00641301, // GFXMMU_LUT63L
+ 0x0000E020, // GFXMMU_LUT63H
+ 0x00651201, // GFXMMU_LUT64L
+ 0x0000E550, // GFXMMU_LUT64H
+ 0x00651201, // GFXMMU_LUT65L
+ 0x0000EA90, // GFXMMU_LUT65H
+ 0x00651201, // GFXMMU_LUT66L
+ 0x0000EFD0, // GFXMMU_LUT66H
+ 0x00651201, // GFXMMU_LUT67L
+ 0x0000F510, // GFXMMU_LUT67H
+ 0x00661101, // GFXMMU_LUT68L
+ 0x0000FA60, // GFXMMU_LUT68H
+ 0x00661101, // GFXMMU_LUT69L
+ 0x0000FFC0, // GFXMMU_LUT69H
+ 0x00661101, // GFXMMU_LUT70L
+ 0x00010520, // GFXMMU_LUT70H
+ 0x00661101, // GFXMMU_LUT71L
+ 0x00010A80, // GFXMMU_LUT71H
+ 0x00671001, // GFXMMU_LUT72L
+ 0x00010FF0, // GFXMMU_LUT72H
+ 0x00671001, // GFXMMU_LUT73L
+ 0x00011570, // GFXMMU_LUT73H
+ 0x00671001, // GFXMMU_LUT74L
+ 0x00011AF0, // GFXMMU_LUT74H
+ 0x00671001, // GFXMMU_LUT75L
+ 0x00012070, // GFXMMU_LUT75H
+ 0x00680F01, // GFXMMU_LUT76L
+ 0x00012600, // GFXMMU_LUT76H
+ 0x00680F01, // GFXMMU_LUT77L
+ 0x00012BA0, // GFXMMU_LUT77H
+ 0x00680F01, // GFXMMU_LUT78L
+ 0x00013140, // GFXMMU_LUT78H
+ 0x00680F01, // GFXMMU_LUT79L
+ 0x000136E0, // GFXMMU_LUT79H
+ 0x00680F01, // GFXMMU_LUT80L
+ 0x00013C80, // GFXMMU_LUT80H
+ 0x00690E01, // GFXMMU_LUT81L
+ 0x00014230, // GFXMMU_LUT81H
+ 0x00690E01, // GFXMMU_LUT82L
+ 0x000147F0, // GFXMMU_LUT82H
+ 0x00690E01, // GFXMMU_LUT83L
+ 0x00014DB0, // GFXMMU_LUT83H
+ 0x00690E01, // GFXMMU_LUT84L
+ 0x00015370, // GFXMMU_LUT84H
+ 0x006A0D01, // GFXMMU_LUT85L
+ 0x00015940, // GFXMMU_LUT85H
+ 0x006A0D01, // GFXMMU_LUT86L
+ 0x00015F20, // GFXMMU_LUT86H
+ 0x006A0D01, // GFXMMU_LUT87L
+ 0x00016500, // GFXMMU_LUT87H
+ 0x006A0D01, // GFXMMU_LUT88L
+ 0x00016AE0, // GFXMMU_LUT88H
+ 0x006A0D01, // GFXMMU_LUT89L
+ 0x000170C0, // GFXMMU_LUT89H
+ 0x006B0C01, // GFXMMU_LUT90L
+ 0x000176B0, // GFXMMU_LUT90H
+ 0x006B0C01, // GFXMMU_LUT91L
+ 0x00017CB0, // GFXMMU_LUT91H
+ 0x006B0C01, // GFXMMU_LUT92L
+ 0x000182B0, // GFXMMU_LUT92H
+ 0x006B0C01, // GFXMMU_LUT93L
+ 0x000188B0, // GFXMMU_LUT93H
+ 0x006B0C01, // GFXMMU_LUT94L
+ 0x00018EB0, // GFXMMU_LUT94H
+ 0x006C0C01, // GFXMMU_LUT95L
+ 0x000194B0, // GFXMMU_LUT95H
+ 0x006C0B01, // GFXMMU_LUT96L
+ 0x00019AD0, // GFXMMU_LUT96H
+ 0x006C0B01, // GFXMMU_LUT97L
+ 0x0001A0F0, // GFXMMU_LUT97H
+ 0x006C0B01, // GFXMMU_LUT98L
+ 0x0001A710, // GFXMMU_LUT98H
+ 0x006C0B01, // GFXMMU_LUT99L
+ 0x0001AD30, // GFXMMU_LUT99H
+ 0x006C0B01, // GFXMMU_LUT100L
+ 0x0001B350, // GFXMMU_LUT100H
+ 0x006D0A01, // GFXMMU_LUT101L
+ 0x0001B980, // GFXMMU_LUT101H
+ 0x006D0A01, // GFXMMU_LUT102L
+ 0x0001BFC0, // GFXMMU_LUT102H
+ 0x006D0A01, // GFXMMU_LUT103L
+ 0x0001C600, // GFXMMU_LUT103H
+ 0x006D0A01, // GFXMMU_LUT104L
+ 0x0001CC40, // GFXMMU_LUT104H
+ 0x006D0A01, // GFXMMU_LUT105L
+ 0x0001D280, // GFXMMU_LUT105H
+ 0x006D0A01, // GFXMMU_LUT106L
+ 0x0001D8C0, // GFXMMU_LUT106H
+ 0x006E0901, // GFXMMU_LUT107L
+ 0x0001DF10, // GFXMMU_LUT107H
+ 0x006E0901, // GFXMMU_LUT108L
+ 0x0001E570, // GFXMMU_LUT108H
+ 0x006E0901, // GFXMMU_LUT109L
+ 0x0001EBD0, // GFXMMU_LUT109H
+ 0x006E0901, // GFXMMU_LUT110L
+ 0x0001F230, // GFXMMU_LUT110H
+ 0x006E0901, // GFXMMU_LUT111L
+ 0x0001F890, // GFXMMU_LUT111H
+ 0x006E0901, // GFXMMU_LUT112L
+ 0x0001FEF0, // GFXMMU_LUT112H
+ 0x006F0801, // GFXMMU_LUT113L
+ 0x00020560, // GFXMMU_LUT113H
+ 0x006F0801, // GFXMMU_LUT114L
+ 0x00020BE0, // GFXMMU_LUT114H
+ 0x006F0801, // GFXMMU_LUT115L
+ 0x00021260, // GFXMMU_LUT115H
+ 0x006F0801, // GFXMMU_LUT116L
+ 0x000218E0, // GFXMMU_LUT116H
+ 0x006F0801, // GFXMMU_LUT117L
+ 0x00021F60, // GFXMMU_LUT117H
+ 0x006F0801, // GFXMMU_LUT118L
+ 0x000225E0, // GFXMMU_LUT118H
+ 0x006F0801, // GFXMMU_LUT119L
+ 0x00022C60, // GFXMMU_LUT119H
+ 0x00700701, // GFXMMU_LUT120L
+ 0x000232F0, // GFXMMU_LUT120H
+ 0x00700701, // GFXMMU_LUT121L
+ 0x00023990, // GFXMMU_LUT121H
+ 0x00700701, // GFXMMU_LUT122L
+ 0x00024030, // GFXMMU_LUT122H
+ 0x00700701, // GFXMMU_LUT123L
+ 0x000246D0, // GFXMMU_LUT123H
+ 0x00700701, // GFXMMU_LUT124L
+ 0x00024D70, // GFXMMU_LUT124H
+ 0x00700701, // GFXMMU_LUT125L
+ 0x00025410, // GFXMMU_LUT125H
+ 0x00700701, // GFXMMU_LUT126L
+ 0x00025AB0, // GFXMMU_LUT126H
+ 0x00710601, // GFXMMU_LUT127L
+ 0x00026160, // GFXMMU_LUT127H
+ 0x00710601, // GFXMMU_LUT128L
+ 0x00026820, // GFXMMU_LUT128H
+ 0x00710601, // GFXMMU_LUT129L
+ 0x00026EE0, // GFXMMU_LUT129H
+ 0x00710601, // GFXMMU_LUT130L
+ 0x000275A0, // GFXMMU_LUT130H
+ 0x00710601, // GFXMMU_LUT131L
+ 0x00027C60, // GFXMMU_LUT131H
+ 0x00710601, // GFXMMU_LUT132L
+ 0x00028320, // GFXMMU_LUT132H
+ 0x00710601, // GFXMMU_LUT133L
+ 0x000289E0, // GFXMMU_LUT133H
+ 0x00710601, // GFXMMU_LUT134L
+ 0x000290A0, // GFXMMU_LUT134H
+ 0x00720501, // GFXMMU_LUT135L
+ 0x00029770, // GFXMMU_LUT135H
+ 0x00720501, // GFXMMU_LUT136L
+ 0x00029E50, // GFXMMU_LUT136H
+ 0x00720501, // GFXMMU_LUT137L
+ 0x0002A530, // GFXMMU_LUT137H
+ 0x00720501, // GFXMMU_LUT138L
+ 0x0002AC10, // GFXMMU_LUT138H
+ 0x00720501, // GFXMMU_LUT139L
+ 0x0002B2F0, // GFXMMU_LUT139H
+ 0x00720501, // GFXMMU_LUT140L
+ 0x0002B9D0, // GFXMMU_LUT140H
+ 0x00720501, // GFXMMU_LUT141L
+ 0x0002C0B0, // GFXMMU_LUT141H
+ 0x00720501, // GFXMMU_LUT142L
+ 0x0002C790, // GFXMMU_LUT142H
+ 0x00720501, // GFXMMU_LUT143L
+ 0x0002CE70, // GFXMMU_LUT143H
+ 0x00730401, // GFXMMU_LUT144L
+ 0x0002D560, // GFXMMU_LUT144H
+ 0x00730401, // GFXMMU_LUT145L
+ 0x0002DC60, // GFXMMU_LUT145H
+ 0x00730401, // GFXMMU_LUT146L
+ 0x0002E360, // GFXMMU_LUT146H
+ 0x00730401, // GFXMMU_LUT147L
+ 0x0002EA60, // GFXMMU_LUT147H
+ 0x00730401, // GFXMMU_LUT148L
+ 0x0002F160, // GFXMMU_LUT148H
+ 0x00730401, // GFXMMU_LUT149L
+ 0x0002F860, // GFXMMU_LUT149H
+ 0x00730401, // GFXMMU_LUT150L
+ 0x0002FF60, // GFXMMU_LUT150H
+ 0x00730401, // GFXMMU_LUT151L
+ 0x00030660, // GFXMMU_LUT151H
+ 0x00730401, // GFXMMU_LUT152L
+ 0x00030D60, // GFXMMU_LUT152H
+ 0x00740301, // GFXMMU_LUT153L
+ 0x00031470, // GFXMMU_LUT153H
+ 0x00740301, // GFXMMU_LUT154L
+ 0x00031B90, // GFXMMU_LUT154H
+ 0x00740301, // GFXMMU_LUT155L
+ 0x000322B0, // GFXMMU_LUT155H
+ 0x00740301, // GFXMMU_LUT156L
+ 0x000329D0, // GFXMMU_LUT156H
+ 0x00740301, // GFXMMU_LUT157L
+ 0x000330F0, // GFXMMU_LUT157H
+ 0x00740301, // GFXMMU_LUT158L
+ 0x00033810, // GFXMMU_LUT158H
+ 0x00740301, // GFXMMU_LUT159L
+ 0x00033F30, // GFXMMU_LUT159H
+ 0x00740301, // GFXMMU_LUT160L
+ 0x00034650, // GFXMMU_LUT160H
+ 0x00740301, // GFXMMU_LUT161L
+ 0x00034D70, // GFXMMU_LUT161H
+ 0x00740301, // GFXMMU_LUT162L
+ 0x00035490, // GFXMMU_LUT162H
+ 0x00740301, // GFXMMU_LUT163L
+ 0x00035BB0, // GFXMMU_LUT163H
+ 0x00740301, // GFXMMU_LUT164L
+ 0x000362D0, // GFXMMU_LUT164H
+ 0x00750201, // GFXMMU_LUT165L
+ 0x00036A00, // GFXMMU_LUT165H
+ 0x00750201, // GFXMMU_LUT166L
+ 0x00037140, // GFXMMU_LUT166H
+ 0x00750201, // GFXMMU_LUT167L
+ 0x00037880, // GFXMMU_LUT167H
+ 0x00750201, // GFXMMU_LUT168L
+ 0x00037FC0, // GFXMMU_LUT168H
+ 0x00750201, // GFXMMU_LUT169L
+ 0x00038700, // GFXMMU_LUT169H
+ 0x00750201, // GFXMMU_LUT170L
+ 0x00038E40, // GFXMMU_LUT170H
+ 0x00750201, // GFXMMU_LUT171L
+ 0x00039580, // GFXMMU_LUT171H
+ 0x00750201, // GFXMMU_LUT172L
+ 0x00039CC0, // GFXMMU_LUT172H
+ 0x00750201, // GFXMMU_LUT173L
+ 0x0003A400, // GFXMMU_LUT173H
+ 0x00750201, // GFXMMU_LUT174L
+ 0x0003AB40, // GFXMMU_LUT174H
+ 0x00750201, // GFXMMU_LUT175L
+ 0x0003B280, // GFXMMU_LUT175H
+ 0x00750201, // GFXMMU_LUT176L
+ 0x0003B9C0, // GFXMMU_LUT176H
+ 0x00750201, // GFXMMU_LUT177L
+ 0x0003C100, // GFXMMU_LUT177H
+ 0x00760101, // GFXMMU_LUT178L
+ 0x0003C850, // GFXMMU_LUT178H
+ 0x00760101, // GFXMMU_LUT179L
+ 0x0003CFB0, // GFXMMU_LUT179H
+ 0x00760101, // GFXMMU_LUT180L
+ 0x0003D710, // GFXMMU_LUT180H
+ 0x00760101, // GFXMMU_LUT181L
+ 0x0003DE70, // GFXMMU_LUT181H
+ 0x00760101, // GFXMMU_LUT182L
+ 0x0003E5D0, // GFXMMU_LUT182H
+ 0x00760101, // GFXMMU_LUT183L
+ 0x0003ED30, // GFXMMU_LUT183H
+ 0x00760101, // GFXMMU_LUT184L
+ 0x0003F490, // GFXMMU_LUT184H
+ 0x00760101, // GFXMMU_LUT185L
+ 0x0003FBF0, // GFXMMU_LUT185H
+ 0x00760101, // GFXMMU_LUT186L
+ 0x00040350, // GFXMMU_LUT186H
+ 0x00760101, // GFXMMU_LUT187L
+ 0x00040AB0, // GFXMMU_LUT187H
+ 0x00760101, // GFXMMU_LUT188L
+ 0x00041210, // GFXMMU_LUT188H
+ 0x00760101, // GFXMMU_LUT189L
+ 0x00041970, // GFXMMU_LUT189H
+ 0x00760101, // GFXMMU_LUT190L
+ 0x000420D0, // GFXMMU_LUT190H
+ 0x00760101, // GFXMMU_LUT191L
+ 0x00042830, // GFXMMU_LUT191H
+ 0x00760101, // GFXMMU_LUT192L
+ 0x00042F90, // GFXMMU_LUT192H
+ 0x00760101, // GFXMMU_LUT193L
+ 0x000436F0, // GFXMMU_LUT193H
+ 0x00760101, // GFXMMU_LUT194L
+ 0x00043E50, // GFXMMU_LUT194H
+ 0x00760101, // GFXMMU_LUT195L
+ 0x000445B0, // GFXMMU_LUT195H
+ 0x00770001, // GFXMMU_LUT196L
+ 0x00044D20, // GFXMMU_LUT196H
+ 0x00770001, // GFXMMU_LUT197L
+ 0x000454A0, // GFXMMU_LUT197H
+ 0x00770001, // GFXMMU_LUT198L
+ 0x00045C20, // GFXMMU_LUT198H
+ 0x00770001, // GFXMMU_LUT199L
+ 0x000463A0, // GFXMMU_LUT199H
+ 0x00770001, // GFXMMU_LUT200L
+ 0x00046B20, // GFXMMU_LUT200H
+ 0x00770001, // GFXMMU_LUT201L
+ 0x000472A0, // GFXMMU_LUT201H
+ 0x00770001, // GFXMMU_LUT202L
+ 0x00047A20, // GFXMMU_LUT202H
+ 0x00770001, // GFXMMU_LUT203L
+ 0x000481A0, // GFXMMU_LUT203H
+ 0x00770001, // GFXMMU_LUT204L
+ 0x00048920, // GFXMMU_LUT204H
+ 0x00770001, // GFXMMU_LUT205L
+ 0x000490A0, // GFXMMU_LUT205H
+ 0x00770001, // GFXMMU_LUT206L
+ 0x00049820, // GFXMMU_LUT206H
+ 0x00770001, // GFXMMU_LUT207L
+ 0x00049FA0, // GFXMMU_LUT207H
+ 0x00770001, // GFXMMU_LUT208L
+ 0x0004A720, // GFXMMU_LUT208H
+ 0x00770001, // GFXMMU_LUT209L
+ 0x0004AEA0, // GFXMMU_LUT209H
+ 0x00770001, // GFXMMU_LUT210L
+ 0x0004B620, // GFXMMU_LUT210H
+ 0x00770001, // GFXMMU_LUT211L
+ 0x0004BDA0, // GFXMMU_LUT211H
+ 0x00770001, // GFXMMU_LUT212L
+ 0x0004C520, // GFXMMU_LUT212H
+ 0x00770001, // GFXMMU_LUT213L
+ 0x0004CCA0, // GFXMMU_LUT213H
+ 0x00770001, // GFXMMU_LUT214L
+ 0x0004D420, // GFXMMU_LUT214H
+ 0x00770001, // GFXMMU_LUT215L
+ 0x0004DBA0, // GFXMMU_LUT215H
+ 0x00770001, // GFXMMU_LUT216L
+ 0x0004E320, // GFXMMU_LUT216H
+ 0x00770001, // GFXMMU_LUT217L
+ 0x0004EAA0, // GFXMMU_LUT217H
+ 0x00770001, // GFXMMU_LUT218L
+ 0x0004F220, // GFXMMU_LUT218H
+ 0x00770001, // GFXMMU_LUT219L
+ 0x0004F9A0, // GFXMMU_LUT219H
+ 0x00770001, // GFXMMU_LUT220L
+ 0x00050120, // GFXMMU_LUT220H
+ 0x00770001, // GFXMMU_LUT221L
+ 0x000508A0, // GFXMMU_LUT221H
+ 0x00770001, // GFXMMU_LUT222L
+ 0x00051020, // GFXMMU_LUT222H
+ 0x00770001, // GFXMMU_LUT223L
+ 0x000517A0, // GFXMMU_LUT223H
+ 0x00770001, // GFXMMU_LUT224L
+ 0x00051F20, // GFXMMU_LUT224H
+ 0x00770001, // GFXMMU_LUT225L
+ 0x000526A0, // GFXMMU_LUT225H
+ 0x00770001, // GFXMMU_LUT226L
+ 0x00052E20, // GFXMMU_LUT226H
+ 0x00770001, // GFXMMU_LUT227L
+ 0x000535A0, // GFXMMU_LUT227H
+ 0x00770001, // GFXMMU_LUT228L
+ 0x00053D20, // GFXMMU_LUT228H
+ 0x00770001, // GFXMMU_LUT229L
+ 0x000544A0, // GFXMMU_LUT229H
+ 0x00770001, // GFXMMU_LUT230L
+ 0x00054C20, // GFXMMU_LUT230H
+ 0x00770001, // GFXMMU_LUT231L
+ 0x000553A0, // GFXMMU_LUT231H
+ 0x00770001, // GFXMMU_LUT232L
+ 0x00055B20, // GFXMMU_LUT232H
+ 0x00770001, // GFXMMU_LUT233L
+ 0x000562A0, // GFXMMU_LUT233H
+ 0x00770001, // GFXMMU_LUT234L
+ 0x00056A20, // GFXMMU_LUT234H
+ 0x00770001, // GFXMMU_LUT235L
+ 0x000571A0, // GFXMMU_LUT235H
+ 0x00770001, // GFXMMU_LUT236L
+ 0x00057920, // GFXMMU_LUT236H
+ 0x00770001, // GFXMMU_LUT237L
+ 0x000580A0, // GFXMMU_LUT237H
+ 0x00770001, // GFXMMU_LUT238L
+ 0x00058820, // GFXMMU_LUT238H
+ 0x00770001, // GFXMMU_LUT239L
+ 0x00058FA0, // GFXMMU_LUT239H
+ 0x00780001, // GFXMMU_LUT240L
+ 0x00059720, // GFXMMU_LUT240H
+ 0x00770001, // GFXMMU_LUT241L
+ 0x00059EB0, // GFXMMU_LUT241H
+ 0x00770001, // GFXMMU_LUT242L
+ 0x0005A630, // GFXMMU_LUT242H
+ 0x00770001, // GFXMMU_LUT243L
+ 0x0005ADB0, // GFXMMU_LUT243H
+ 0x00770001, // GFXMMU_LUT244L
+ 0x0005B530, // GFXMMU_LUT244H
+ 0x00770001, // GFXMMU_LUT245L
+ 0x0005BCB0, // GFXMMU_LUT245H
+ 0x00770001, // GFXMMU_LUT246L
+ 0x0005C430, // GFXMMU_LUT246H
+ 0x00770001, // GFXMMU_LUT247L
+ 0x0005CBB0, // GFXMMU_LUT247H
+ 0x00770001, // GFXMMU_LUT248L
+ 0x0005D330, // GFXMMU_LUT248H
+ 0x00770001, // GFXMMU_LUT249L
+ 0x0005DAB0, // GFXMMU_LUT249H
+ 0x00770001, // GFXMMU_LUT250L
+ 0x0005E230, // GFXMMU_LUT250H
+ 0x00770001, // GFXMMU_LUT251L
+ 0x0005E9B0, // GFXMMU_LUT251H
+ 0x00770001, // GFXMMU_LUT252L
+ 0x0005F130, // GFXMMU_LUT252H
+ 0x00770001, // GFXMMU_LUT253L
+ 0x0005F8B0, // GFXMMU_LUT253H
+ 0x00770001, // GFXMMU_LUT254L
+ 0x00060030, // GFXMMU_LUT254H
+ 0x00770001, // GFXMMU_LUT255L
+ 0x000607B0, // GFXMMU_LUT255H
+ 0x00770001, // GFXMMU_LUT256L
+ 0x00060F30, // GFXMMU_LUT256H
+ 0x00770001, // GFXMMU_LUT257L
+ 0x000616B0, // GFXMMU_LUT257H
+ 0x00770001, // GFXMMU_LUT258L
+ 0x00061E30, // GFXMMU_LUT258H
+ 0x00770001, // GFXMMU_LUT259L
+ 0x000625B0, // GFXMMU_LUT259H
+ 0x00770001, // GFXMMU_LUT260L
+ 0x00062D30, // GFXMMU_LUT260H
+ 0x00770001, // GFXMMU_LUT261L
+ 0x000634B0, // GFXMMU_LUT261H
+ 0x00770001, // GFXMMU_LUT262L
+ 0x00063C30, // GFXMMU_LUT262H
+ 0x00770001, // GFXMMU_LUT263L
+ 0x000643B0, // GFXMMU_LUT263H
+ 0x00770001, // GFXMMU_LUT264L
+ 0x00064B30, // GFXMMU_LUT264H
+ 0x00770001, // GFXMMU_LUT265L
+ 0x000652B0, // GFXMMU_LUT265H
+ 0x00770001, // GFXMMU_LUT266L
+ 0x00065A30, // GFXMMU_LUT266H
+ 0x00770001, // GFXMMU_LUT267L
+ 0x000661B0, // GFXMMU_LUT267H
+ 0x00770001, // GFXMMU_LUT268L
+ 0x00066930, // GFXMMU_LUT268H
+ 0x00770001, // GFXMMU_LUT269L
+ 0x000670B0, // GFXMMU_LUT269H
+ 0x00770001, // GFXMMU_LUT270L
+ 0x00067830, // GFXMMU_LUT270H
+ 0x00770001, // GFXMMU_LUT271L
+ 0x00067FB0, // GFXMMU_LUT271H
+ 0x00770001, // GFXMMU_LUT272L
+ 0x00068730, // GFXMMU_LUT272H
+ 0x00770001, // GFXMMU_LUT273L
+ 0x00068EB0, // GFXMMU_LUT273H
+ 0x00770001, // GFXMMU_LUT274L
+ 0x00069630, // GFXMMU_LUT274H
+ 0x00770001, // GFXMMU_LUT275L
+ 0x00069DB0, // GFXMMU_LUT275H
+ 0x00770001, // GFXMMU_LUT276L
+ 0x0006A530, // GFXMMU_LUT276H
+ 0x00770001, // GFXMMU_LUT277L
+ 0x0006ACB0, // GFXMMU_LUT277H
+ 0x00770001, // GFXMMU_LUT278L
+ 0x0006B430, // GFXMMU_LUT278H
+ 0x00770001, // GFXMMU_LUT279L
+ 0x0006BBB0, // GFXMMU_LUT279H
+ 0x00770001, // GFXMMU_LUT280L
+ 0x0006C330, // GFXMMU_LUT280H
+ 0x00770001, // GFXMMU_LUT281L
+ 0x0006CAB0, // GFXMMU_LUT281H
+ 0x00770001, // GFXMMU_LUT282L
+ 0x0006D230, // GFXMMU_LUT282H
+ 0x00770001, // GFXMMU_LUT283L
+ 0x0006D9B0, // GFXMMU_LUT283H
+ 0x00770001, // GFXMMU_LUT284L
+ 0x0006E130, // GFXMMU_LUT284H
+ 0x00760101, // GFXMMU_LUT285L
+ 0x0006E8A0, // GFXMMU_LUT285H
+ 0x00760101, // GFXMMU_LUT286L
+ 0x0006F000, // GFXMMU_LUT286H
+ 0x00760101, // GFXMMU_LUT287L
+ 0x0006F760, // GFXMMU_LUT287H
+ 0x00760101, // GFXMMU_LUT288L
+ 0x0006FEC0, // GFXMMU_LUT288H
+ 0x00760101, // GFXMMU_LUT289L
+ 0x00070620, // GFXMMU_LUT289H
+ 0x00760101, // GFXMMU_LUT290L
+ 0x00070D80, // GFXMMU_LUT290H
+ 0x00760101, // GFXMMU_LUT291L
+ 0x000714E0, // GFXMMU_LUT291H
+ 0x00760101, // GFXMMU_LUT292L
+ 0x00071C40, // GFXMMU_LUT292H
+ 0x00760101, // GFXMMU_LUT293L
+ 0x000723A0, // GFXMMU_LUT293H
+ 0x00760101, // GFXMMU_LUT294L
+ 0x00072B00, // GFXMMU_LUT294H
+ 0x00760101, // GFXMMU_LUT295L
+ 0x00073260, // GFXMMU_LUT295H
+ 0x00760101, // GFXMMU_LUT296L
+ 0x000739C0, // GFXMMU_LUT296H
+ 0x00760101, // GFXMMU_LUT297L
+ 0x00074120, // GFXMMU_LUT297H
+ 0x00760101, // GFXMMU_LUT298L
+ 0x00074880, // GFXMMU_LUT298H
+ 0x00760101, // GFXMMU_LUT299L
+ 0x00074FE0, // GFXMMU_LUT299H
+ 0x00760101, // GFXMMU_LUT300L
+ 0x00075740, // GFXMMU_LUT300H
+ 0x00760101, // GFXMMU_LUT301L
+ 0x00075EA0, // GFXMMU_LUT301H
+ 0x00760101, // GFXMMU_LUT302L
+ 0x00076600, // GFXMMU_LUT302H
+ 0x00750201, // GFXMMU_LUT303L
+ 0x00076D50, // GFXMMU_LUT303H
+ 0x00750201, // GFXMMU_LUT304L
+ 0x00077490, // GFXMMU_LUT304H
+ 0x00750201, // GFXMMU_LUT305L
+ 0x00077BD0, // GFXMMU_LUT305H
+ 0x00750201, // GFXMMU_LUT306L
+ 0x00078310, // GFXMMU_LUT306H
+ 0x00750201, // GFXMMU_LUT307L
+ 0x00078A50, // GFXMMU_LUT307H
+ 0x00750201, // GFXMMU_LUT308L
+ 0x00079190, // GFXMMU_LUT308H
+ 0x00750201, // GFXMMU_LUT309L
+ 0x000798D0, // GFXMMU_LUT309H
+ 0x00750201, // GFXMMU_LUT310L
+ 0x0007A010, // GFXMMU_LUT310H
+ 0x00750201, // GFXMMU_LUT311L
+ 0x0007A750, // GFXMMU_LUT311H
+ 0x00750201, // GFXMMU_LUT312L
+ 0x0007AE90, // GFXMMU_LUT312H
+ 0x00750201, // GFXMMU_LUT313L
+ 0x0007B5D0, // GFXMMU_LUT313H
+ 0x00750201, // GFXMMU_LUT314L
+ 0x0007BD10, // GFXMMU_LUT314H
+ 0x00750201, // GFXMMU_LUT315L
+ 0x0007C450, // GFXMMU_LUT315H
+ 0x00740301, // GFXMMU_LUT316L
+ 0x0007CB80, // GFXMMU_LUT316H
+ 0x00740301, // GFXMMU_LUT317L
+ 0x0007D2A0, // GFXMMU_LUT317H
+ 0x00740301, // GFXMMU_LUT318L
+ 0x0007D9C0, // GFXMMU_LUT318H
+ 0x00740301, // GFXMMU_LUT319L
+ 0x0007E0E0, // GFXMMU_LUT319H
+ 0x00740301, // GFXMMU_LUT320L
+ 0x0007E800, // GFXMMU_LUT320H
+ 0x00740301, // GFXMMU_LUT321L
+ 0x0007EF20, // GFXMMU_LUT321H
+ 0x00740301, // GFXMMU_LUT322L
+ 0x0007F640, // GFXMMU_LUT322H
+ 0x00740301, // GFXMMU_LUT323L
+ 0x0007FD60, // GFXMMU_LUT323H
+ 0x00740301, // GFXMMU_LUT324L
+ 0x00080480, // GFXMMU_LUT324H
+ 0x00740301, // GFXMMU_LUT325L
+ 0x00080BA0, // GFXMMU_LUT325H
+ 0x00740301, // GFXMMU_LUT326L
+ 0x000812C0, // GFXMMU_LUT326H
+ 0x00740301, // GFXMMU_LUT327L
+ 0x000819E0, // GFXMMU_LUT327H
+ 0x00730401, // GFXMMU_LUT328L
+ 0x000820F0, // GFXMMU_LUT328H
+ 0x00730401, // GFXMMU_LUT329L
+ 0x000827F0, // GFXMMU_LUT329H
+ 0x00730401, // GFXMMU_LUT330L
+ 0x00082EF0, // GFXMMU_LUT330H
+ 0x00730401, // GFXMMU_LUT331L
+ 0x000835F0, // GFXMMU_LUT331H
+ 0x00730401, // GFXMMU_LUT332L
+ 0x00083CF0, // GFXMMU_LUT332H
+ 0x00730401, // GFXMMU_LUT333L
+ 0x000843F0, // GFXMMU_LUT333H
+ 0x00730401, // GFXMMU_LUT334L
+ 0x00084AF0, // GFXMMU_LUT334H
+ 0x00730401, // GFXMMU_LUT335L
+ 0x000851F0, // GFXMMU_LUT335H
+ 0x00730401, // GFXMMU_LUT336L
+ 0x000858F0, // GFXMMU_LUT336H
+ 0x00730401, // GFXMMU_LUT337L
+ 0x00085FF0, // GFXMMU_LUT337H
+ 0x00720501, // GFXMMU_LUT338L
+ 0x000866E0, // GFXMMU_LUT338H
+ 0x00720501, // GFXMMU_LUT339L
+ 0x00086DC0, // GFXMMU_LUT339H
+ 0x00720501, // GFXMMU_LUT340L
+ 0x000874A0, // GFXMMU_LUT340H
+ 0x00720501, // GFXMMU_LUT341L
+ 0x00087B80, // GFXMMU_LUT341H
+ 0x00720501, // GFXMMU_LUT342L
+ 0x00088260, // GFXMMU_LUT342H
+ 0x00720501, // GFXMMU_LUT343L
+ 0x00088940, // GFXMMU_LUT343H
+ 0x00720501, // GFXMMU_LUT344L
+ 0x00089020, // GFXMMU_LUT344H
+ 0x00720501, // GFXMMU_LUT345L
+ 0x00089700, // GFXMMU_LUT345H
+ 0x00710601, // GFXMMU_LUT346L
+ 0x00089DD0, // GFXMMU_LUT346H
+ 0x00710601, // GFXMMU_LUT347L
+ 0x0008A490, // GFXMMU_LUT347H
+ 0x00710601, // GFXMMU_LUT348L
+ 0x0008AB50, // GFXMMU_LUT348H
+ 0x00710601, // GFXMMU_LUT349L
+ 0x0008B210, // GFXMMU_LUT349H
+ 0x00710601, // GFXMMU_LUT350L
+ 0x0008B8D0, // GFXMMU_LUT350H
+ 0x00710601, // GFXMMU_LUT351L
+ 0x0008BF90, // GFXMMU_LUT351H
+ 0x00710601, // GFXMMU_LUT352L
+ 0x0008C650, // GFXMMU_LUT352H
+ 0x00710601, // GFXMMU_LUT353L
+ 0x0008CD10, // GFXMMU_LUT353H
+ 0x00700701, // GFXMMU_LUT354L
+ 0x0008D3C0, // GFXMMU_LUT354H
+ 0x00700701, // GFXMMU_LUT355L
+ 0x0008DA60, // GFXMMU_LUT355H
+ 0x00700701, // GFXMMU_LUT356L
+ 0x0008E100, // GFXMMU_LUT356H
+ 0x00700701, // GFXMMU_LUT357L
+ 0x0008E7A0, // GFXMMU_LUT357H
+ 0x00700701, // GFXMMU_LUT358L
+ 0x0008EE40, // GFXMMU_LUT358H
+ 0x00700701, // GFXMMU_LUT359L
+ 0x0008F4E0, // GFXMMU_LUT359H
+ 0x00700701, // GFXMMU_LUT360L
+ 0x0008FB80, // GFXMMU_LUT360H
+ 0x006F0801, // GFXMMU_LUT361L
+ 0x00090210, // GFXMMU_LUT361H
+ 0x006F0801, // GFXMMU_LUT362L
+ 0x00090890, // GFXMMU_LUT362H
+ 0x006F0801, // GFXMMU_LUT363L
+ 0x00090F10, // GFXMMU_LUT363H
+ 0x006F0801, // GFXMMU_LUT364L
+ 0x00091590, // GFXMMU_LUT364H
+ 0x006F0801, // GFXMMU_LUT365L
+ 0x00091C10, // GFXMMU_LUT365H
+ 0x006F0801, // GFXMMU_LUT366L
+ 0x00092290, // GFXMMU_LUT366H
+ 0x006F0801, // GFXMMU_LUT367L
+ 0x00092910, // GFXMMU_LUT367H
+ 0x006E0901, // GFXMMU_LUT368L
+ 0x00092F80, // GFXMMU_LUT368H
+ 0x006E0901, // GFXMMU_LUT369L
+ 0x000935E0, // GFXMMU_LUT369H
+ 0x006E0901, // GFXMMU_LUT370L
+ 0x00093C40, // GFXMMU_LUT370H
+ 0x006E0901, // GFXMMU_LUT371L
+ 0x000942A0, // GFXMMU_LUT371H
+ 0x006E0901, // GFXMMU_LUT372L
+ 0x00094900, // GFXMMU_LUT372H
+ 0x006E0901, // GFXMMU_LUT373L
+ 0x00094F60, // GFXMMU_LUT373H
+ 0x006D0A01, // GFXMMU_LUT374L
+ 0x000955B0, // GFXMMU_LUT374H
+ 0x006D0A01, // GFXMMU_LUT375L
+ 0x00095BF0, // GFXMMU_LUT375H
+ 0x006D0A01, // GFXMMU_LUT376L
+ 0x00096230, // GFXMMU_LUT376H
+ 0x006D0A01, // GFXMMU_LUT377L
+ 0x00096870, // GFXMMU_LUT377H
+ 0x006D0A01, // GFXMMU_LUT378L
+ 0x00096EB0, // GFXMMU_LUT378H
+ 0x006C0B01, // GFXMMU_LUT379L
+ 0x000974E0, // GFXMMU_LUT379H
+ 0x006C0B01, // GFXMMU_LUT380L
+ 0x00097B00, // GFXMMU_LUT380H
+ 0x006C0B01, // GFXMMU_LUT381L
+ 0x00098120, // GFXMMU_LUT381H
+ 0x006C0B01, // GFXMMU_LUT382L
+ 0x00098740, // GFXMMU_LUT382H
+ 0x006C0B01, // GFXMMU_LUT383L
+ 0x00098D60, // GFXMMU_LUT383H
+ 0x006C0B01, // GFXMMU_LUT384L
+ 0x00099380, // GFXMMU_LUT384H
+ 0x006B0C01, // GFXMMU_LUT385L
+ 0x00099990, // GFXMMU_LUT385H
+ 0x006B0C01, // GFXMMU_LUT386L
+ 0x00099F90, // GFXMMU_LUT386H
+ 0x006B0C01, // GFXMMU_LUT387L
+ 0x0009A590, // GFXMMU_LUT387H
+ 0x006B0C01, // GFXMMU_LUT388L
+ 0x0009AB90, // GFXMMU_LUT388H
+ 0x006B0C01, // GFXMMU_LUT389L
+ 0x0009B190, // GFXMMU_LUT389H
+ 0x006A0D01, // GFXMMU_LUT390L
+ 0x0009B780, // GFXMMU_LUT390H
+ 0x006A0D01, // GFXMMU_LUT391L
+ 0x0009BD60, // GFXMMU_LUT391H
+ 0x006A0D01, // GFXMMU_LUT392L
+ 0x0009C340, // GFXMMU_LUT392H
+ 0x006A0D01, // GFXMMU_LUT393L
+ 0x0009C920, // GFXMMU_LUT393H
+ 0x006A0D01, // GFXMMU_LUT394L
+ 0x0009CF00, // GFXMMU_LUT394H
+ 0x00690E01, // GFXMMU_LUT395L
+ 0x0009D4D0, // GFXMMU_LUT395H
+ 0x00690E01, // GFXMMU_LUT396L
+ 0x0009DA90, // GFXMMU_LUT396H
+ 0x00690E01, // GFXMMU_LUT397L
+ 0x0009E050, // GFXMMU_LUT397H
+ 0x00690E01, // GFXMMU_LUT398L
+ 0x0009E610, // GFXMMU_LUT398H
+ 0x00690E01, // GFXMMU_LUT399L
+ 0x0009EBD0, // GFXMMU_LUT399H
+ 0x00690E01, // GFXMMU_LUT400L
+ 0x0009F190, // GFXMMU_LUT400H
+ 0x00690E01, // GFXMMU_LUT401L
+ 0x0009F750, // GFXMMU_LUT401H
+ 0x00680F01, // GFXMMU_LUT402L
+ 0x0009FD00, // GFXMMU_LUT402H
+ 0x00680F01, // GFXMMU_LUT403L
+ 0x000A02A0, // GFXMMU_LUT403H
+ 0x00680F01, // GFXMMU_LUT404L
+ 0x000A0840, // GFXMMU_LUT404H
+ 0x00680F01, // GFXMMU_LUT405L
+ 0x000A0DE0, // GFXMMU_LUT405H
+ 0x00671001, // GFXMMU_LUT406L
+ 0x000A1370, // GFXMMU_LUT406H
+ 0x00671001, // GFXMMU_LUT407L
+ 0x000A18F0, // GFXMMU_LUT407H
+ 0x00671001, // GFXMMU_LUT408L
+ 0x000A1E70, // GFXMMU_LUT408H
+ 0x00671001, // GFXMMU_LUT409L
+ 0x000A23F0, // GFXMMU_LUT409H
+ 0x00661101, // GFXMMU_LUT410L
+ 0x000A2960, // GFXMMU_LUT410H
+ 0x00661101, // GFXMMU_LUT411L
+ 0x000A2EC0, // GFXMMU_LUT411H
+ 0x00661101, // GFXMMU_LUT412L
+ 0x000A3420, // GFXMMU_LUT412H
+ 0x00661101, // GFXMMU_LUT413L
+ 0x000A3980, // GFXMMU_LUT413H
+ 0x00651201, // GFXMMU_LUT414L
+ 0x000A3ED0, // GFXMMU_LUT414H
+ 0x00651201, // GFXMMU_LUT415L
+ 0x000A4410, // GFXMMU_LUT415H
+ 0x00651201, // GFXMMU_LUT416L
+ 0x000A4950, // GFXMMU_LUT416H
+ 0x00641301, // GFXMMU_LUT417L
+ 0x000A4E80, // GFXMMU_LUT417H
+ 0x00641301, // GFXMMU_LUT418L
+ 0x000A53A0, // GFXMMU_LUT418H
+ 0x00641301, // GFXMMU_LUT419L
+ 0x000A58C0, // GFXMMU_LUT419H
+ 0x00641301, // GFXMMU_LUT420L
+ 0x000A5DE0, // GFXMMU_LUT420H
+ 0x00631401, // GFXMMU_LUT421L
+ 0x000A62F0, // GFXMMU_LUT421H
+ 0x00631401, // GFXMMU_LUT422L
+ 0x000A67F0, // GFXMMU_LUT422H
+ 0x00631401, // GFXMMU_LUT423L
+ 0x000A6CF0, // GFXMMU_LUT423H
+ 0x00621501, // GFXMMU_LUT424L
+ 0x000A71E0, // GFXMMU_LUT424H
+ 0x00621501, // GFXMMU_LUT425L
+ 0x000A76C0, // GFXMMU_LUT425H
+ 0x00621501, // GFXMMU_LUT426L
+ 0x000A7BA0, // GFXMMU_LUT426H
+ 0x00621501, // GFXMMU_LUT427L
+ 0x000A8080, // GFXMMU_LUT427H
+ 0x00611601, // GFXMMU_LUT428L
+ 0x000A8550, // GFXMMU_LUT428H
+ 0x00611601, // GFXMMU_LUT429L
+ 0x000A8A10, // GFXMMU_LUT429H
+ 0x00611601, // GFXMMU_LUT430L
+ 0x000A8ED0, // GFXMMU_LUT430H
+ 0x00601701, // GFXMMU_LUT431L
+ 0x000A9380, // GFXMMU_LUT431H
+ 0x00601701, // GFXMMU_LUT432L
+ 0x000A9820, // GFXMMU_LUT432H
+ 0x00601701, // GFXMMU_LUT433L
+ 0x000A9CC0, // GFXMMU_LUT433H
+ 0x005F1801, // GFXMMU_LUT434L
+ 0x000AA150, // GFXMMU_LUT434H
+ 0x005F1801, // GFXMMU_LUT435L
+ 0x000AA5D0, // GFXMMU_LUT435H
+ 0x005F1801, // GFXMMU_LUT436L
+ 0x000AAA50, // GFXMMU_LUT436H
+ 0x005E1901, // GFXMMU_LUT437L
+ 0x000AAEC0, // GFXMMU_LUT437H
+ 0x005E1901, // GFXMMU_LUT438L
+ 0x000AB320, // GFXMMU_LUT438H
+ 0x005D1A01, // GFXMMU_LUT439L
+ 0x000AB770, // GFXMMU_LUT439H
+ 0x005D1A01, // GFXMMU_LUT440L
+ 0x000ABBB0, // GFXMMU_LUT440H
+ 0x005D1A01, // GFXMMU_LUT441L
+ 0x000ABFF0, // GFXMMU_LUT441H
+ 0x005C1B01, // GFXMMU_LUT442L
+ 0x000AC420, // GFXMMU_LUT442H
+ 0x005C1B01, // GFXMMU_LUT443L
+ 0x000AC840, // GFXMMU_LUT443H
+ 0x005B1C01, // GFXMMU_LUT444L
+ 0x000ACC50, // GFXMMU_LUT444H
+ 0x005B1C01, // GFXMMU_LUT445L
+ 0x000AD050, // GFXMMU_LUT445H
+ 0x005B1C01, // GFXMMU_LUT446L
+ 0x000AD450, // GFXMMU_LUT446H
+ 0x005A1D01, // GFXMMU_LUT447L
+ 0x000AD840, // GFXMMU_LUT447H
+ 0x005A1D01, // GFXMMU_LUT448L
+ 0x000ADC20, // GFXMMU_LUT448H
+ 0x00591E01, // GFXMMU_LUT449L
+ 0x000ADFF0, // GFXMMU_LUT449H
+ 0x00591E01, // GFXMMU_LUT450L
+ 0x000AE3B0, // GFXMMU_LUT450H
+ 0x00581F01, // GFXMMU_LUT451L
+ 0x000AE760, // GFXMMU_LUT451H
+ 0x00581F01, // GFXMMU_LUT452L
+ 0x000AEB00, // GFXMMU_LUT452H
+ 0x00572001, // GFXMMU_LUT453L
+ 0x000AEE90, // GFXMMU_LUT453H
+ 0x00572001, // GFXMMU_LUT454L
+ 0x000AF210, // GFXMMU_LUT454H
+ 0x00562101, // GFXMMU_LUT455L
+ 0x000AF580, // GFXMMU_LUT455H
+ 0x00562101, // GFXMMU_LUT456L
+ 0x000AF8E0, // GFXMMU_LUT456H
+ 0x00552201, // GFXMMU_LUT457L
+ 0x000AFC30, // GFXMMU_LUT457H
+ 0x00552201, // GFXMMU_LUT458L
+ 0x000AFF70, // GFXMMU_LUT458H
+ 0x00542301, // GFXMMU_LUT459L
+ 0x000B02A0, // GFXMMU_LUT459H
+ 0x00542301, // GFXMMU_LUT460L
+ 0x000B05C0, // GFXMMU_LUT460H
+ 0x00532401, // GFXMMU_LUT461L
+ 0x000B08D0, // GFXMMU_LUT461H
+ 0x00522501, // GFXMMU_LUT462L
+ 0x000B0BC0, // GFXMMU_LUT462H
+ 0x00522501, // GFXMMU_LUT463L
+ 0x000B0EA0, // GFXMMU_LUT463H
+ 0x00512601, // GFXMMU_LUT464L
+ 0x000B1170, // GFXMMU_LUT464H
+ 0x00502701, // GFXMMU_LUT465L
+ 0x000B1420, // GFXMMU_LUT465H
+ 0x00502701, // GFXMMU_LUT466L
+ 0x000B16C0, // GFXMMU_LUT466H
+ 0x004F2801, // GFXMMU_LUT467L
+ 0x000B1950, // GFXMMU_LUT467H
+ 0x004E2901, // GFXMMU_LUT468L
+ 0x000B1BC0, // GFXMMU_LUT468H
+ 0x004D2A01, // GFXMMU_LUT469L
+ 0x000B1E10, // GFXMMU_LUT469H
+ 0x004D2A01, // GFXMMU_LUT470L
+ 0x000B2050, // GFXMMU_LUT470H
+ 0x004C2B01, // GFXMMU_LUT471L
+ 0x000B2280, // GFXMMU_LUT471H
+ 0x004B2C01, // GFXMMU_LUT472L
+ 0x000B2490, // GFXMMU_LUT472H
+ 0x004A2D01, // GFXMMU_LUT473L
+ 0x000B2680, // GFXMMU_LUT473H
+ 0x00492E01, // GFXMMU_LUT474L
+ 0x000B2850, // GFXMMU_LUT474H
+ 0x00482F01, // GFXMMU_LUT475L
+ 0x000B2A00, // GFXMMU_LUT475H
+ 0x00463101, // GFXMMU_LUT476L
+ 0x000B2B80, // GFXMMU_LUT476H
+ 0x00453201, // GFXMMU_LUT477L
+ 0x000B2CD0, // GFXMMU_LUT477H
+ 0x00433401, // GFXMMU_LUT478L
+ 0x000B2DF0, // GFXMMU_LUT478H
+ 0x00413601, // GFXMMU_LUT479L
+ 0x000B2ED0 // GFXMMU_LUT479H
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*__ gfxmmu_lut_H */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_internal.h b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_internal.h
new file mode 100644
index 000000000..45a934ed0
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_internal.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
+#define TREZOR_HAL_DISPLAY_INTERNAL_H
+
+#include
+
+// Size of the physical frame buffer in bytes
+//
+// It's smaller than size of the virtual framebuffer
+// due to used GFXMMU settings
+#define PHYSICAL_FRAME_BUFFER_SIZE 184320
+
+// Physical frame buffers in internal SRAM memory
+//
+// Both frame buffers layes in the fixed addresses that
+// are shared between bootloaders and the firmware.
+extern uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
+extern uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
+
+// The current frame buffer selector at fixed memory address
+//
+// The variable address is shared between bootloaders and the firmware
+extern uint32_t current_frame_buffer;
+
+// LCD orientations
+#define LCD_ORIENTATION_PORTRAIT 0U
+#define LCD_ORIENTATION_LANDSCAPE 1U
+#define LCD_ORIENTATION_PORTRAIT_ROT180 2U
+#define LCD_ORIENTATION_LANDSCAPE_ROT180 3U
+
+int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation);
+int32_t BSP_LCD_Reinit(uint32_t Instance);
+int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness);
+int32_t BSP_LCD_DisplayOn(uint32_t Instance);
+int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr);
+
+#endif // TREZOR_HAL_DISPLAY_INTERNAL_H
diff --git a/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c
new file mode 100644
index 000000000..aad64772d
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c
@@ -0,0 +1,1562 @@
+/**
+ ******************************************************************************
+ * @file stm32u5x9j_discovery_lcd.c
+ * @author MCD Application Team
+ * @brief This file includes the driver for Liquid Crystal Display (LCD)
+ module
+ * mounted on MB1829A board (ARGB8888 color format).
+ @verbatim
+ 1. How To use this driver:
+ --------------------------
+ - This driver is used to drive directly in command mode a LCD TFT using the
+ DSI interface.
+ The following IPs are implied : DSI Host IP block working
+ in conjunction to the LTDC controller.
+ - This driver is linked by construction to LCD.
+
+ 2. Driver description:
+ ----------------------
+ + Initialization steps:
+ o Initialize the LCD using the BSP_LCD_Init() function. You can select
+ display orientation with "Orientation" parameter (portrait, landscape,
+ portrait with 180 degrees rotation or landscape with 180 degrees
+ rotation).
+ o Call BSP_LCD_GetXSize() and BSP_LCD_GetYsize() to get respectively
+ width and height in pixels of LCD in the current orientation.
+ o Call BSP_LCD_SetBrightness() and BSP_LCD_GetBrightness() to
+ respectively set and get LCD brightness.
+ o Call BSP_LCD_SetActiveLayer() to select the current active layer.
+ o Call BSP_LCD_GetFormat() to get LCD pixel format supported.
+
+ + Display on LCD:
+ o Call BSP_LCD_DisplayOn() and BSP_LCD_DisplayOff() to respectively
+ switch on and switch off the LCD display.
+ o First, check that frame buffer is available using
+ BSP_LCD_IsFrameBufferAvailable(). o When frame buffer is available, modify it
+ using following functions: o Call BSP_LCD_WritePixel() and BSP_LCD_ReadPixel()
+ to respectively write and read a pixel. o Call BSP_LCD_DrawHLine() to draw a
+ horizontal line. o Call BSP_LCD_DrawVLine() to draw a vertical line. o Call
+ BSP_LCD_DrawBitmap() to draw a bitmap. o Call BSP_LCD_FillRect() to draw a
+ rectangle. o Call BSP_LCD_FillRGBRect() to draw a rectangle with RGB buffer.
+ o Call BSP_LCD_Refresh() to refresh LCD display.
+
+ + De-initialization steps:
+ o De-initialize the LCD using the BSP_LCD_DeInit() function.
+
+ @endverbatim
+ ******************************************************************************
+ * @attention
+ *
+ * Copyright (c) 2023 STMicroelectronics.
+ * All rights reserved.
+ *
+ * This software is licensed under terms that can be found in the LICENSE file
+ * in the root directory of this software component.
+ * If no LICENSE file comes with this software, it is provided AS-IS.
+ *
+ ******************************************************************************
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "colors.h"
+#include "stdint.h"
+#include "string.h"
+
+#include TREZOR_BOARD
+#include STM32_HAL_H
+
+#include "display_internal.h"
+
+/* Common Error codes */
+#define BSP_ERROR_NONE 0
+#define BSP_ERROR_NO_INIT -1
+#define BSP_ERROR_WRONG_PARAM -2
+#define BSP_ERROR_BUSY -3
+#define BSP_ERROR_PERIPH_FAILURE -4
+#define BSP_ERROR_COMPONENT_FAILURE -5
+#define BSP_ERROR_UNKNOWN_FAILURE -6
+#define BSP_ERROR_UNKNOWN_COMPONENT -7
+#define BSP_ERROR_BUS_FAILURE -8
+#define BSP_ERROR_CLOCK_FAILURE -9
+#define BSP_ERROR_MSP_FAILURE -10
+#define BSP_ERROR_FEATURE_NOT_SUPPORTED -11
+
+#define BSP_ERROR_BUS_ACKNOWLEDGE_FAILURE (-102)
+/* Button user interrupt priority */
+#define BSP_BUTTON_USER_IT_PRIORITY \
+ 0x0FUL /* Default is lowest priority level */
+
+/* LCD interrupt priorities */
+#define BSP_LCD_GFXMMU_IT_PRIORITY \
+ 0x0FUL /* Default is lowest priority level \
+ */
+#define BSP_LCD_LTDC_IT_PRIORITY 0x0FUL /* Default is lowest priority level */
+#define BSP_LCD_DSI_IT_PRIORITY 0x0FUL /* Default is lowest priority level */
+
+/* HSPI RAM interrupt priority */
+#define BSP_HSPI_RAM_IT_PRIORITY 0x0FUL /* Default is lowest priority level */
+#define LCD_PIXEL_FORMAT_ARGB8888 \
+ 0x00000000U /*!< ARGB8888 LTDC pixel format \
+ */
+#define LCD_PIXEL_FORMAT_RGB888 0x00000001U /*!< RGB888 LTDC pixel format */
+#define LCD_PIXEL_FORMAT_RGB565 0x00000002U /*!< RGB565 LTDC pixel format */
+#define LCD_PIXEL_FORMAT_ARGB1555 \
+ 0x00000003U /*!< ARGB1555 LTDC pixel format \
+ */
+#define LCD_PIXEL_FORMAT_ARGB4444 \
+ 0x00000004U /*!< ARGB4444 LTDC pixel format \
+ */
+#define LCD_PIXEL_FORMAT_L8 0x00000005U /*!< L8 LTDC pixel format */
+#define LCD_PIXEL_FORMAT_AL44 0x00000006U /*!< AL44 LTDC pixel format */
+#define LCD_PIXEL_FORMAT_AL88 0x00000007U /*!< AL88 LTDC pixel format */
+/* LCD instances */
+#define LCD_INSTANCES_NBR 1U
+
+#define DSI_POWERON_GPIO_PORT GPIOI
+#define DSI_POWERON_GPIO_PIN GPIO_PIN_5
+#define DSI_POWERON_GPIO_CLOCK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
+
+#define DSI_RESET_GPIO_PORT GPIOD
+#define DSI_RESET_GPIO_PIN GPIO_PIN_5
+#define DSI_RESET_GPIO_CLOCK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
+
+#define VSYNC 1
+#define VBP 12
+#define VFP 50
+#define VACT 481
+#define HSYNC 2
+#define HBP 1
+#define HFP 1
+#define HACT 480
+#define LCD_WIDTH 480
+#define LCD_HEIGHT 480
+#define PIXEL_PER_LINE 768U
+
+#include "display_gfxmmu_lut.h"
+
+/** @addtogroup BSP
+ * @{
+ */
+
+/** @addtogroup STM32U5x9J_DISCOVERY
+ * @{
+ */
+
+/** @defgroup STM32U5x9J_DISCOVERY_LCD LCD
+ * @{
+ */
+
+/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Defines LCD Private Constants
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Variables LCD Private Variables
+ * @{
+ */
+
+#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1)
+static uint32_t LcdGfxmmu_IsMspCbValid[LCD_INSTANCES_NBR] = {0};
+#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1) */
+
+#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1)
+static uint32_t LcdLtdc_IsMspCbValid[LCD_INSTANCES_NBR] = {0};
+#endif /* (USE_HAL_LTDC_REGISTER_CALLBACKS == 1) */
+
+#if (USE_HAL_DSI_REGISTER_CALLBACKS == 1)
+static uint32_t LcdDsi_IsMspCbValid[LCD_INSTANCES_NBR] = {0};
+#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 1) */
+
+GFXMMU_HandleTypeDef hlcd_gfxmmu = {0};
+LTDC_HandleTypeDef hlcd_ltdc = {0};
+DSI_HandleTypeDef hlcd_dsi = {0};
+static DSI_VidCfgTypeDef DSIVidCfg = {0};
+
+/**
+ * @}
+ */
+
+/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_FunctionPrototypes LCD Private
+ * Function Prototypes
+ * @{
+ */
+static int32_t LCD_Init(void);
+static int32_t LCD_DeInit(void);
+
+static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu);
+static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu);
+static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc);
+static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc);
+static void DSI_MspInit(DSI_HandleTypeDef *hdsi);
+static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi);
+#if (USE_HAL_DSI_REGISTER_CALLBACKS == 1)
+static void DSI_EndOfRefreshCallback(DSI_HandleTypeDef *hdsi);
+#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 1) */
+/**
+ * @}
+ */
+
+/** @addtogroup STM32U5x9J_DISCOVERY_LCD_Exported_Functions
+ * @{
+ */
+/**
+ * @brief Initialize the LCD.
+ * @param Instance LCD Instance.
+ * @param Orientation LCD_ORIENTATION_PORTRAIT, LCD_ORIENTATION_LANDSCAPE,
+ * LCD_ORIENTATION_PORTRAIT_ROT180 or
+ * LCD_ORIENTATION_LANDSCAPE_ROT180.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if ((Instance >= LCD_INSTANCES_NBR) ||
+ (Orientation > LCD_ORIENTATION_LANDSCAPE_ROT180)) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else if ((Orientation == LCD_ORIENTATION_LANDSCAPE) ||
+ (Orientation == LCD_ORIENTATION_LANDSCAPE_ROT180)) {
+ status = BSP_ERROR_FEATURE_NOT_SUPPORTED;
+ } else {
+ if (LCD_Init() != 0) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief De-Initialize the LCD.
+ * @param Instance LCD Instance.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_DeInit(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ if (LCD_DeInit() != 0) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief Set the display on.
+ * @param Instance LCD Instance.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_DisplayOn(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ /* Set the display on */
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1,
+ DSI_SET_DISPLAY_ON, 0x00) != HAL_OK) {
+ status = BSP_ERROR_WRONG_PARAM;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief Set the display off.
+ * @param Instance LCD Instance.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_DisplayOff(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ /* Set the display off */
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1,
+ DSI_SET_DISPLAY_OFF, 0x00) != HAL_OK) {
+ status = BSP_ERROR_WRONG_PARAM;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief Set the display brightness.
+ * @param Instance LCD Instance.
+ * @param Brightness [00: Min (black), 100 Max].
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness) {
+ int32_t status;
+
+ if ((Instance >= LCD_INSTANCES_NBR) || (Brightness > 100U)) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ status = BSP_ERROR_FEATURE_NOT_SUPPORTED;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Get the display brightness.
+ * @param Instance LCD Instance.
+ * @param Brightness [00: Min (black), 100 Max].
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_GetBrightness(uint32_t Instance, uint32_t *Brightness) {
+ int32_t status;
+
+ if ((Instance >= LCD_INSTANCES_NBR) || (Brightness == NULL)) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ status = BSP_ERROR_FEATURE_NOT_SUPPORTED;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Get the LCD X size.
+ * @param Instance LCD Instance.
+ * @param Xsize LCD X size.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_GetXSize(uint32_t Instance, uint32_t *Xsize) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if ((Instance >= LCD_INSTANCES_NBR) || (Xsize == NULL)) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ /* Get the display Xsize */
+ *Xsize = LCD_WIDTH;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Get the LCD Y size.
+ * @param Instance LCD Instance.
+ * @param Ysize LCD Y size.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_GetYSize(uint32_t Instance, uint32_t *Ysize) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if ((Instance >= LCD_INSTANCES_NBR) || (Ysize == NULL)) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ /* Get the display Ysize */
+ *Ysize = LCD_HEIGHT;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Set the LCD active layer.
+ * @param Instance LCD Instance.
+ * @param LayerIndex Active layer index.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_SetActiveLayer(uint32_t Instance, uint32_t LayerIndex) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ /* Nothing to do */
+ UNUSED(LayerIndex);
+ }
+
+ return status;
+}
+
+/**
+ * @brief Get pixel format supported by LCD.
+ * @param Instance LCD Instance.
+ * @param Format Pointer on pixel format.
+ * @retval BSP status.
+ */
+int32_t BSP_LCD_GetFormat(uint32_t Instance, uint32_t *Format) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ /* Get pixel format supported by LCD */
+ *Format = LCD_PIXEL_FORMAT_ARGB8888;
+ }
+
+ return status;
+}
+
+void MX_GFXMMU_Reinit(GFXMMU_HandleTypeDef *hgfxmmu) {
+ /* Initialize GFXMMU */
+ hgfxmmu->Instance = GFXMMU;
+ hgfxmmu->Init.BlocksPerLine = GFXMMU_192BLOCKS;
+ hgfxmmu->Init.DefaultValue = 0xFFFFFFFFU;
+ hgfxmmu->Init.Buffers.Buf0Address = (uint32_t)physical_frame_buffer_0;
+ hgfxmmu->Init.Buffers.Buf1Address = (uint32_t)physical_frame_buffer_1;
+ hgfxmmu->Init.Buffers.Buf2Address = 0;
+ hgfxmmu->Init.Buffers.Buf3Address = 0;
+#if defined(GFXMMU_CR_CE)
+ hgfxmmu->Init.CachePrefetch.Activation = DISABLE;
+ hgfxmmu->Init.CachePrefetch.CacheLock = GFXMMU_CACHE_LOCK_DISABLE;
+ hgfxmmu->Init.CachePrefetch.CacheLockBuffer =
+ GFXMMU_CACHE_LOCK_BUFFER0; /* NU */
+ hgfxmmu->Init.CachePrefetch.CacheForce = GFXMMU_CACHE_FORCE_ENABLE; /* NU */
+ hgfxmmu->Init.CachePrefetch.OutterBufferability =
+ GFXMMU_OUTTER_BUFFERABILITY_DISABLE;
+ hgfxmmu->Init.CachePrefetch.OutterCachability =
+ GFXMMU_OUTTER_CACHABILITY_DISABLE;
+ hgfxmmu->Init.CachePrefetch.Prefetch = GFXMMU_PREFETCH_DISABLE;
+#endif /* GFXMMU_CR_CE */
+#if defined(GFXMMU_CR_ACE)
+ hgfxmmu->Init.AddressCache.Activation = DISABLE;
+ hgfxmmu->Init.AddressCache.AddressCacheLockBuffer =
+ GFXMMU_ADDRESSCACHE_LOCK_BUFFER0;
+#endif /* GFXMMU_CR_ACE */
+ hgfxmmu->Init.Interrupts.Activation = DISABLE;
+ hgfxmmu->Init.Interrupts.UsedInterrupts = GFXMMU_AHB_MASTER_ERROR_IT; /* NU */
+}
+
+/**
+ * @brief MX GFXMMU initialization.
+ * @param hgfxmmu GFXMMU handle.
+ * @retval HAL status.
+ */
+__weak HAL_StatusTypeDef MX_GFXMMU_Init(GFXMMU_HandleTypeDef *hgfxmmu) {
+ MX_GFXMMU_Reinit(hgfxmmu);
+ return HAL_GFXMMU_Init(hgfxmmu);
+}
+
+/**
+ * @brief MX LTDC clock configuration.
+ * @param hltdc LTDC handle.
+ * @retval HAL status.
+ */
+__weak HAL_StatusTypeDef MX_LTDC_ClockConfig(LTDC_HandleTypeDef *hltdc) {
+ RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0};
+
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(hltdc);
+
+ /* Start and configurre PLL3 */
+ /* HSE = 16MHZ */
+ /* 16/(M=4) = 4MHz input (min) */
+ /* 4*(N=125) = 500MHz VCO (almost max) */
+ /* 500/(P=8) = 62.5 for DSI ie exactly the lane byte clock*/
+ /* 500/(R=24) = 20.83 for LTDC exact match with DSI bandwidth */
+ PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
+ PLL3InitPeriph.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3;
+ PLL3InitPeriph.PLL3.PLL3M = 4;
+ PLL3InitPeriph.PLL3.PLL3N = 125;
+ PLL3InitPeriph.PLL3.PLL3P = 8;
+ PLL3InitPeriph.PLL3.PLL3Q = 8;
+ PLL3InitPeriph.PLL3.PLL3R = 24;
+ PLL3InitPeriph.PLL3.PLL3FRACN = 0;
+ PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1;
+ PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP;
+ PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
+ return HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph);
+}
+
+void MX_LTDC_Reinit(LTDC_HandleTypeDef *hltdc) {
+ /* LTDC initialization */
+ hltdc->Instance = LTDC;
+ hltdc->Init.HSPolarity = LTDC_HSPOLARITY_AL;
+ hltdc->Init.VSPolarity = LTDC_VSPOLARITY_AL;
+ hltdc->Init.DEPolarity = LTDC_DEPOLARITY_AL;
+ hltdc->Init.PCPolarity = LTDC_PCPOLARITY_IPC;
+ hltdc->Init.HorizontalSync = HSYNC - 1;
+ hltdc->Init.AccumulatedHBP = HSYNC + HBP - 1;
+ hltdc->Init.AccumulatedActiveW = HACT + HBP + HSYNC - 1;
+ hltdc->Init.TotalWidth = HACT + HBP + HFP + HSYNC - 1;
+ hltdc->Init.Backcolor.Red = 0; /* Not used default value */
+ hltdc->Init.Backcolor.Green = 0; /* Not used default value */
+ hltdc->Init.Backcolor.Blue = 0; /* Not used default value */
+ hltdc->Init.Backcolor.Reserved = 0xFF;
+
+ HAL_LTDCEx_StructInitFromVideoConfig(&hlcd_ltdc, &DSIVidCfg);
+}
+
+/**
+ * @brief MX LTDC initialization.
+ * @param hltdc LTDC handle.
+ * @retval HAL status.
+ */
+__weak HAL_StatusTypeDef MX_LTDC_Init(LTDC_HandleTypeDef *hltdc) {
+ MX_LTDC_Reinit(hltdc);
+
+ return HAL_LTDC_Init(hltdc);
+}
+
+// HAL_StatusTypeDef MX_LTDC_ReConfigLayer(LTDC_HandleTypeDef *hltdc, uint32_t
+// LayerIndex)
+//{
+// LTDC_LayerCfgTypeDef LayerCfg = {0};
+//
+///* LTDC layer configuration */
+// LayerCfg.WindowX0 = 0;
+// LayerCfg.WindowX1 = LCD_WIDTH;
+// LayerCfg.WindowY0 = 1;
+// LayerCfg.WindowY1 = (uint32_t)LCD_HEIGHT + 1UL;
+// LayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
+// LayerCfg.Alpha = 0xFF; /* NU default value */
+// LayerCfg.Alpha0 = 0; /* NU default value */
+// LayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default
+// value */ LayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA; /* Not
+// Used: default value */ LayerCfg.FBStartAdress =
+// GFXMMU_VIRTUAL_BUFFER0_BASE; LayerCfg.ImageWidth = PIXEL_PER_LINE; /*
+// Number of pixels per line in virtual frame buffer */ LayerCfg.ImageHeight =
+// LCD_HEIGHT; LayerCfg.Backcolor.Red = 0; /* Not Used: default value */
+// LayerCfg.Backcolor.Green = 0; /* Not Used: default value */
+// LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */
+// LayerCfg.Bac
+// return HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LayerIndex);kcolor.Reserved =
+// 0xFF;
+//}
+
+/**
+ * @brief MX LTDC layer configuration.
+ * @param hltdc LTDC handle.
+ * @param LayerIndex LTDC layer index.
+ * @retval HAL status.
+ */
+__weak HAL_StatusTypeDef MX_LTDC_ConfigLayer(LTDC_HandleTypeDef *hltdc,
+ uint32_t LayerIndex,
+ uint32_t fb_addr) {
+ LTDC_LayerCfgTypeDef LayerCfg = {0};
+
+ /* LTDC layer configuration */
+ LayerCfg.WindowX0 = 0;
+ LayerCfg.WindowX1 = LCD_WIDTH;
+ LayerCfg.WindowY0 = 1;
+ LayerCfg.WindowY1 = (uint32_t)LCD_HEIGHT + 1UL;
+ LayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
+ LayerCfg.Alpha = 0xFF; /* NU default value */
+ LayerCfg.Alpha0 = 0; /* NU default value */
+ LayerCfg.BlendingFactor1 =
+ LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default value */
+ LayerCfg.BlendingFactor2 =
+ LTDC_BLENDING_FACTOR2_PAxCA; /* Not Used: default value */
+ LayerCfg.FBStartAdress = fb_addr;
+ LayerCfg.ImageWidth =
+ PIXEL_PER_LINE; /* Number of pixels per line in virtual frame buffer */
+ LayerCfg.ImageHeight = LCD_HEIGHT;
+ LayerCfg.Backcolor.Red = 0; /* Not Used: default value */
+ LayerCfg.Backcolor.Green = 0; /* Not Used: default value */
+ LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */
+ LayerCfg.Backcolor.Reserved = 0xFF;
+ return HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LayerIndex);
+}
+
+/**
+ * @brief MX DSI initialization.
+ * @param hdsi DSI handle.
+ * @retval HAL status.
+ */
+HAL_StatusTypeDef MX_DSI_Reinit(DSI_HandleTypeDef *hdsi) {
+ /* DSI initialization */
+ hdsi->Instance = DSI;
+ hdsi->Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE;
+ /* We have 1 data lane at 500Mbps => lane byte clock at 500/8 = 62,5 MHZ */
+ /* We want TX escape clock at around 20MHz and under 20MHz so clock division
+ * is set to 4 */
+ hdsi->Init.TXEscapeCkdiv = 4;
+ hdsi->Init.NumberOfLanes = DSI_TWO_DATA_LANES;
+ hdsi->Init.PHYFrequencyRange = DSI_DPHY_FRANGE_450MHZ_510MHZ;
+ hdsi->Init.PHYLowPowerOffset = 0;
+
+ /* Configure the DSI for Video mode */
+ DSIVidCfg.VirtualChannelID = 0;
+ DSIVidCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
+ DSIVidCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
+ DSIVidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
+ DSIVidCfg.ColorCoding = DSI_RGB888;
+ DSIVidCfg.Mode = DSI_VID_MODE_BURST;
+ DSIVidCfg.PacketSize = LCD_WIDTH;
+ DSIVidCfg.NullPacketSize = 0xFFFU;
+ DSIVidCfg.HorizontalSyncActive = HSYNC * 3;
+ DSIVidCfg.HorizontalBackPorch = HBP * 3;
+ DSIVidCfg.HorizontalLine = (HACT + HSYNC + HBP + HFP) * 3;
+ DSIVidCfg.VerticalSyncActive = VSYNC;
+ DSIVidCfg.VerticalBackPorch = VBP;
+ DSIVidCfg.VerticalFrontPorch = VFP;
+ DSIVidCfg.VerticalActive = VACT;
+ DSIVidCfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE;
+ DSIVidCfg.LPLargestPacketSize = 64;
+ /* Specify for each region of the video frame, if the transmission of command
+ * in LP mode is allowed in this region */
+ /* while streaming is active in video mode */
+ DSIVidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;
+ DSIVidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE;
+ DSIVidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;
+ DSIVidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;
+ DSIVidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;
+ DSIVidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE;
+ DSIVidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_ENABLE;
+ DSIVidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE;
+
+ return HAL_OK;
+}
+
+/**
+ * @brief MX DSI initialization.
+ * @param hdsi DSI handle.
+ * @retval HAL status.
+ */
+__weak HAL_StatusTypeDef MX_DSI_Init(DSI_HandleTypeDef *hdsi) {
+ DSI_PLLInitTypeDef PLLInit = {0};
+
+ /* DSI initialization */
+ hdsi->Instance = DSI;
+ hdsi->Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE;
+ /* We have 1 data lane at 500Mbps => lane byte clock at 500/8 = 62,5 MHZ */
+ /* We want TX escape clock at around 20MHz and under 20MHz so clock division
+ * is set to 4 */
+ hdsi->Init.TXEscapeCkdiv = 4;
+ hdsi->Init.NumberOfLanes = DSI_TWO_DATA_LANES;
+ hdsi->Init.PHYFrequencyRange = DSI_DPHY_FRANGE_450MHZ_510MHZ;
+ hdsi->Init.PHYLowPowerOffset = 0;
+
+ PLLInit.PLLNDIV = 125;
+ PLLInit.PLLIDF = 4;
+ PLLInit.PLLODF = 2;
+ PLLInit.PLLVCORange = DSI_DPHY_VCO_FRANGE_800MHZ_1GHZ;
+ PLLInit.PLLChargePump = DSI_PLL_CHARGE_PUMP_2000HZ_4400HZ;
+ PLLInit.PLLTuning = DSI_PLL_LOOP_FILTER_2000HZ_4400HZ;
+
+ if (HAL_DSI_Init(hdsi, &PLLInit) != HAL_OK) {
+ return HAL_ERROR;
+ }
+
+ if (HAL_DSI_SetGenericVCID(&hlcd_dsi, 0) != HAL_OK) {
+ return HAL_ERROR;
+ }
+
+ /* Configure the DSI for Video mode */
+ DSIVidCfg.VirtualChannelID = 0;
+ DSIVidCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
+ DSIVidCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
+ DSIVidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
+ DSIVidCfg.ColorCoding = DSI_RGB888;
+ DSIVidCfg.Mode = DSI_VID_MODE_BURST;
+ DSIVidCfg.PacketSize = LCD_WIDTH;
+ DSIVidCfg.NullPacketSize = 0xFFFU;
+ DSIVidCfg.HorizontalSyncActive = HSYNC * 3;
+ DSIVidCfg.HorizontalBackPorch = HBP * 3;
+ DSIVidCfg.HorizontalLine = (HACT + HSYNC + HBP + HFP) * 3;
+ DSIVidCfg.VerticalSyncActive = VSYNC;
+ DSIVidCfg.VerticalBackPorch = VBP;
+ DSIVidCfg.VerticalFrontPorch = VFP;
+ DSIVidCfg.VerticalActive = VACT;
+ DSIVidCfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE;
+ DSIVidCfg.LPLargestPacketSize = 64;
+ /* Specify for each region of the video frame, if the transmission of command
+ * in LP mode is allowed in this region */
+ /* while streaming is active in video mode */
+ DSIVidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;
+ DSIVidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE;
+ DSIVidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;
+ DSIVidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;
+ DSIVidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;
+ DSIVidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE;
+ DSIVidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_ENABLE;
+ DSIVidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE;
+
+ /* Drive the display */
+ if (HAL_DSI_ConfigVideoMode(&hlcd_dsi, &DSIVidCfg) != HAL_OK) {
+ return HAL_ERROR;
+ }
+
+ return HAL_OK;
+}
+
+/**
+ * @brief MX DMA2D initialization.
+ * @param hdma2d DMA2D handle.
+ * @param Mode DMA2D transfer mode.
+ * @param OffLine DMA2D output offset.
+ * @retval HAL status.
+ */
+__weak HAL_StatusTypeDef MX_DMA2D_Init(DMA2D_HandleTypeDef *hdma2d,
+ uint32_t Mode, uint32_t OffLine) {
+ /* Register to memory mode with ARGB8888 as color Mode */
+ hdma2d->Instance = DMA2D;
+ hdma2d->Init.Mode = Mode;
+ hdma2d->Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
+ hdma2d->Init.OutputOffset = OffLine;
+ hdma2d->Init.AlphaInverted = DMA2D_REGULAR_ALPHA;
+ hdma2d->Init.RedBlueSwap = DMA2D_RB_REGULAR;
+ hdma2d->Init.BytesSwap = DMA2D_BYTES_REGULAR;
+ hdma2d->Init.LineOffsetMode = DMA2D_LOM_PIXELS;
+
+ /* DMA2D Initialization */
+ return HAL_DMA2D_Init(hdma2d);
+}
+
+#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 1)
+/**
+ * @brief Register Default LCD GFXMMU Msp Callbacks
+ * @retval BSP status
+ */
+int32_t BSP_LCD_GFXMMU_RegisterDefaultMspCallbacks(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_GFXMMU_RESET_HANDLE_STATE(&hlcd_gfxmmu);
+
+ /* Register default MspInit/MspDeInit Callback */
+ if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, HAL_GFXMMU_MSPINIT_CB_ID,
+ GFXMMU_MspInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu,
+ HAL_GFXMMU_MSPDEINIT_CB_ID,
+ GFXMMU_MspDeInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdGfxmmu_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+
+/**
+ * @brief Register LCD GFXMMU Msp Callback
+ * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions
+ * @retval BSP status
+ */
+int32_t BSP_LCD_GFXMMU_RegisterMspCallbacks(uint32_t Instance,
+ BSP_LCD_GFXMMU_Cb_t *Callback) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_GFXMMU_RESET_HANDLE_STATE(&hlcd_gfxmmu);
+
+ /* Register MspInit/MspDeInit Callbacks */
+ if (HAL_GFXMMU_RegisterCallback(&hlcd_gfxmmu, HAL_GFXMMU_MSPINIT_CB_ID,
+ Callback->pMspGfxmmuInitCb) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_GFXMMU_RegisterCallback(
+ &hlcd_gfxmmu, HAL_GFXMMU_MSPDEINIT_CB_ID,
+ Callback->pMspGfxmmuDeInitCb) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdGfxmmu_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+#endif /* USE_HAL_GFXMMU_REGISTER_CALLBACKS */
+
+#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 1)
+/**
+ * @brief Register Default LCD LTDC Msp Callbacks
+ * @retval BSP status
+ */
+int32_t BSP_LCD_LTDC_RegisterDefaultMspCallbacks(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_LTDC_RESET_HANDLE_STATE(&hlcd_ltdc);
+
+ /* Register default MspInit/MspDeInit Callback */
+ if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPINIT_CB_ID,
+ LTDC_MspInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPDEINIT_CB_ID,
+ LTDC_MspDeInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdLtdc_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+
+/**
+ * @brief Register LCD LTDC Msp Callback
+ * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions
+ * @retval BSP status
+ */
+int32_t BSP_LCD_LTDC_RegisterMspCallbacks(uint32_t Instance,
+ BSP_LCD_LTDC_Cb_t *Callback) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_LTDC_RESET_HANDLE_STATE(&hlcd_ltdc);
+
+ /* Register MspInit/MspDeInit Callbacks */
+ if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPINIT_CB_ID,
+ Callback->pMspLtdcInitCb) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_LTDC_RegisterCallback(&hlcd_ltdc, HAL_LTDC_MSPDEINIT_CB_ID,
+ Callback->pMspLtdcDeInitCb) !=
+ HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdLtdc_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+#endif /* USE_HAL_LTDC_REGISTER_CALLBACKS */
+
+#if (USE_HAL_DSI_REGISTER_CALLBACKS == 1)
+/**
+ * @brief Register Default LCD DSI Msp Callbacks
+ * @retval BSP status
+ */
+int32_t BSP_LCD_DSI_RegisterDefaultMspCallbacks(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_DSI_RESET_HANDLE_STATE(&hlcd_dsi);
+
+ /* Register default MspInit/MspDeInit Callback */
+ if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPINIT_CB_ID,
+ DSI_MspInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPDEINIT_CB_ID,
+ DSI_MspDeInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdDsi_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+
+/**
+ * @brief Register LCD DSI Msp Callback
+ * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions
+ * @retval BSP status
+ */
+int32_t BSP_LCD_DSI_RegisterMspCallbacks(uint32_t Instance,
+ BSP_LCD_DSI_Cb_t *Callback) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_DSI_RESET_HANDLE_STATE(&hlcd_dsi);
+
+ /* Register MspInit/MspDeInit Callbacks */
+ if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPINIT_CB_ID,
+ Callback->pMspDsiInitCb) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_DSI_RegisterCallback(&hlcd_dsi, HAL_DSI_MSPDEINIT_CB_ID,
+ Callback->pMspDsiDeInitCb) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdDsi_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+#endif /* USE_HAL_DSI_REGISTER_CALLBACKS */
+
+#if (USE_HAL_DMA2D_REGISTER_CALLBACKS == 1)
+/**
+ * @brief Register Default LCD DMA2D Msp Callbacks
+ * @retval BSP status
+ */
+int32_t BSP_LCD_DMA2D_RegisterDefaultMspCallbacks(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_DMA2D_RESET_HANDLE_STATE(&hlcd_dma2d);
+
+ /* Register default MspInit/MspDeInit Callback */
+ if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, HAL_DMA2D_MSPINIT_CB_ID,
+ DMA2D_MspInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d,
+ HAL_DMA2D_MSPDEINIT_CB_ID,
+ DMA2D_MspDeInit) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdDma2d_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+
+/**
+ * @brief Register LCD DMA2D Msp Callback
+ * @param Callbacks pointer to LCD MspInit/MspDeInit callback functions
+ * @retval BSP status
+ */
+int32_t BSP_LCD_DMA2D_RegisterMspCallbacks(uint32_t Instance,
+ BSP_LCD_DMA2D_Cb_t *Callback) {
+ int32_t status = BSP_ERROR_NONE;
+
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ __HAL_DMA2D_RESET_HANDLE_STATE(&hlcd_dma2d);
+
+ /* Register MspInit/MspDeInit Callbacks */
+ if (HAL_DMA2D_RegisterCallback(&hlcd_dma2d, HAL_DMA2D_MSPINIT_CB_ID,
+ Callback->pMspDma2dInitCb) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else if (HAL_DMA2D_RegisterCallback(
+ &hlcd_dma2d, HAL_DMA2D_MSPDEINIT_CB_ID,
+ Callback->pMspDma2dDeInitCb) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ LcdDma2d_IsMspCbValid[Instance] = 1U;
+ }
+ }
+
+ /* BSP status */
+ return status;
+}
+#endif /* USE_HAL_DMA2D_REGISTER_CALLBACKS */
+/**
+ * @}
+ */
+
+/** @defgroup STM32U5x9J_DISCOVERY_LCD_Private_Functions LCD Private Functions
+ * @{
+ */
+
+/**
+ * @brief Initialize LCD.
+ * @retval BSP status.
+ */
+static int32_t LCD_Init(void) {
+ int32_t status = BSP_ERROR_NONE;
+ uint32_t ErrorNumber = 0;
+ DSI_PHY_TimerTypeDef PhyTimers = {0};
+ DSI_HOST_TimeoutTypeDef HostTimeouts = {0};
+
+ /***************/
+ /* GFXMMU init */
+ /***************/
+#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0)
+ GFXMMU_MspInit(&hlcd_gfxmmu);
+#else
+ /* Register the GFXMMU MSP Callbacks */
+ if (LcdGfxmmu_IsMspCbValid[0] == 0U) {
+ if (BSP_LCD_GFXMMU_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */
+
+ if (status == BSP_ERROR_NONE) {
+ /* GFXMMU peripheral initialization */
+ if (MX_GFXMMU_Init(&hlcd_gfxmmu) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ /* Initialize LUT */
+ else if (HAL_GFXMMU_ConfigLut(&hlcd_gfxmmu, 0, LCD_WIDTH,
+ (uint32_t)&gfxmmu_lut) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ /* Disable non visible lines : from line 480 to 1023 */
+ if (HAL_OK != HAL_GFXMMU_DisableLutLines(&hlcd_gfxmmu, LCD_WIDTH, 544)) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+ }
+
+ /************/
+ /* DSI init */
+ /************/
+ if (status == BSP_ERROR_NONE) {
+#if (USE_HAL_DSI_REGISTER_CALLBACKS == 0)
+ DSI_MspInit(&hlcd_dsi);
+#else
+ /* Register the DSI MSP Callbacks */
+ if (LcdDsi_IsMspCbValid[0] == 0U) {
+ if (BSP_LCD_DSI_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 0) */
+
+ if (status == BSP_ERROR_NONE) {
+ /* DSI peripheral initialization */
+ if (MX_DSI_Init(&hlcd_dsi) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+ }
+
+ /*********************/
+ /* LCD configuration */
+ /*********************/
+ if (status == BSP_ERROR_NONE) {
+ PhyTimers.ClockLaneHS2LPTime = 11;
+ PhyTimers.ClockLaneLP2HSTime = 40;
+ PhyTimers.DataLaneHS2LPTime = 12;
+ PhyTimers.DataLaneLP2HSTime = 23;
+ PhyTimers.DataLaneMaxReadTime = 0;
+ PhyTimers.StopWaitTime = 7;
+
+ if (HAL_DSI_ConfigPhyTimer(&hlcd_dsi, &PhyTimers) != HAL_OK) {
+ return 6;
+ }
+
+ HostTimeouts.TimeoutCkdiv = 1;
+ HostTimeouts.HighSpeedTransmissionTimeout = 0;
+ HostTimeouts.LowPowerReceptionTimeout = 0;
+ HostTimeouts.HighSpeedReadTimeout = 0;
+ HostTimeouts.LowPowerReadTimeout = 0;
+ HostTimeouts.HighSpeedWriteTimeout = 0;
+ HostTimeouts.HighSpeedWritePrespMode = 0;
+ HostTimeouts.LowPowerWriteTimeout = 0;
+ HostTimeouts.BTATimeout = 0;
+
+ if (HAL_DSI_ConfigHostTimeouts(&hlcd_dsi, &HostTimeouts) != HAL_OK) {
+ return 7;
+ }
+
+ if (HAL_DSI_ConfigFlowControl(&hlcd_dsi, DSI_FLOW_CONTROL_BTA) != HAL_OK) {
+ return 7;
+ }
+
+ /* Enable the DSI host */
+ __HAL_DSI_ENABLE(&hlcd_dsi);
+
+ /*************/
+ /* LTDC init */
+ /*************/
+ if (status == BSP_ERROR_NONE) {
+ if (MX_LTDC_ClockConfig(&hlcd_ltdc) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 0)
+ LTDC_MspInit(&hlcd_ltdc);
+#else
+ /* Register the LTDC MSP Callbacks */
+ if (LcdLtdc_IsMspCbValid[0] == 0U) {
+ if (BSP_LCD_LTDC_RegisterDefaultMspCallbacks(0) != BSP_ERROR_NONE) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */
+
+ if (status == BSP_ERROR_NONE) {
+ /* LTDC peripheral initialization */
+ if (MX_LTDC_Init(&hlcd_ltdc) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ } else {
+ if (MX_LTDC_ConfigLayer(&hlcd_ltdc, LTDC_LAYER_1,
+ GFXMMU_VIRTUAL_BUFFER0_BASE_S) != HAL_OK) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+ }
+ }
+ }
+
+ /* Start DSI */
+ if (HAL_DSI_Start(&(hlcd_dsi)) != HAL_OK) {
+ return 8;
+ }
+
+ /* CMD Mode */
+ uint8_t InitParam1[3] = {0xFF, 0x83, 0x79};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB9,
+ InitParam1) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* SETPOWER */
+ uint8_t InitParam2[16] = {0x44, 0x1C, 0x1C, 0x37, 0x57, 0x90, 0xD0, 0xE2,
+ 0x58, 0x80, 0x38, 0x38, 0xF8, 0x33, 0x34, 0x42};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 16, 0xB1,
+ InitParam2) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* SETDISP */
+ uint8_t InitParam3[9] = {0x80, 0x14, 0x0C, 0x30, 0x20,
+ 0x50, 0x11, 0x42, 0x1D};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 9, 0xB2,
+ InitParam3) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* Set display cycle timing */
+ uint8_t InitParam4[10] = {0x01, 0xAA, 0x01, 0xAF, 0x01,
+ 0xAF, 0x10, 0xEA, 0x1C, 0xEA};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 10, 0xB4,
+ InitParam4) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* SETVCOM */
+ uint8_t InitParam5[4] = {00, 00, 00, 0xC0};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 4, 0xC7,
+ InitParam5) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* Set Panel Related Registers */
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xCC,
+ 0x02) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xD2,
+ 0x77) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ uint8_t InitParam6[37] = {0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x32,
+ 0x10, 0x01, 0x00, 0x01, 0x03, 0x72, 0x03, 0x72,
+ 0x00, 0x08, 0x00, 0x08, 0x33, 0x33, 0x05, 0x05,
+ 0x37, 0x05, 0x05, 0x37, 0x0A, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x01, 0x00, 0x0E};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 37, 0xD3,
+ InitParam6) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ uint8_t InitParam7[34] = {
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
+ 0x18, 0x18, 0x19, 0x19, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
+ 0x23, 0x22, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 34, 0xD5,
+ InitParam7) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ uint8_t InitParam8[32] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x19, 0x19, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
+ 0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
+ 0x20, 0x21, 0x22, 0x23, 0x18, 0x18, 0x18, 0x18};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 35, 0xD6,
+ InitParam8) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* SET GAMMA */
+ uint8_t InitParam9[42] = {
+ 0x00, 0x16, 0x1B, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0D, 0x0F,
+ 0x18, 0x0E, 0x11, 0x12, 0x11, 0x14, 0x07, 0x12, 0x13, 0x18, 0x00,
+ 0x17, 0x1C, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0C, 0x0F, 0x18,
+ 0x0E, 0x11, 0x14, 0x11, 0x12, 0x07, 0x12, 0x14, 0x18};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xE0,
+ InitParam9) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ uint8_t InitParam10[3] = {0x2C, 0x2C, 00};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB6,
+ InitParam10) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD,
+ 0x00) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ uint8_t InitParam11[] = {
+ 0x01, 0x00, 0x07, 0x0F, 0x16, 0x1F, 0x27, 0x30, 0x38, 0x40, 0x47,
+ 0x4E, 0x56, 0x5D, 0x65, 0x6D, 0x74, 0x7D, 0x84, 0x8A, 0x90, 0x99,
+ 0xA1, 0xA9, 0xB0, 0xB6, 0xBD, 0xC4, 0xCD, 0xD4, 0xDD, 0xE5, 0xEC,
+ 0xF3, 0x36, 0x07, 0x1C, 0xC0, 0x1B, 0x01, 0xF1, 0x34, 0x00};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1,
+ InitParam11) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD,
+ 0x01) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ uint8_t InitParam12[] = {
+ 0x00, 0x08, 0x0F, 0x16, 0x1F, 0x28, 0x31, 0x39, 0x41, 0x48, 0x51,
+ 0x59, 0x60, 0x68, 0x70, 0x78, 0x7F, 0x87, 0x8D, 0x94, 0x9C, 0xA3,
+ 0xAB, 0xB3, 0xB9, 0xC1, 0xC8, 0xD0, 0xD8, 0xE0, 0xE8, 0xEE, 0xF5,
+ 0x3B, 0x1A, 0xB6, 0xA0, 0x07, 0x45, 0xC5, 0x37, 0x00};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1,
+ InitParam12) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD,
+ 0x02) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ uint8_t InitParam13[42] = {
+ 0x00, 0x09, 0x0F, 0x18, 0x21, 0x2A, 0x34, 0x3C, 0x45, 0x4C, 0x56,
+ 0x5E, 0x66, 0x6E, 0x76, 0x7E, 0x87, 0x8E, 0x95, 0x9D, 0xA6, 0xAF,
+ 0xB7, 0xBD, 0xC5, 0xCE, 0xD5, 0xDF, 0xE7, 0xEE, 0xF4, 0xFA, 0xFF,
+ 0x0C, 0x31, 0x83, 0x3C, 0x5B, 0x56, 0x1E, 0x5A, 0xFF};
+ if (HAL_DSI_LongWrite(&hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1,
+ InitParam13) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD,
+ 0x00) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* Exit Sleep Mode*/
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x11,
+ 0x00) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ HAL_Delay(120);
+
+ /* Display On */
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x29,
+ 0x00) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ HAL_Delay(120);
+
+ if (ErrorNumber != 0U) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * @brief De-Initialize LCD.
+ * @retval BSP status.
+ */
+static int32_t LCD_DeInit(void) {
+ int32_t status = BSP_ERROR_NONE;
+ uint32_t ErrorNumber = 0;
+
+ /* Disable DSI wrapper */
+ __HAL_DSI_WRAPPER_DISABLE(&hlcd_dsi);
+
+ /* Set display off */
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1,
+ DSI_SET_DISPLAY_OFF, 0x00) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ /* Wait before entering in sleep mode */
+ HAL_Delay(2000);
+
+ /* Put LCD in sleep mode */
+ if (HAL_DSI_ShortWrite(&hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0,
+ DSI_ENTER_SLEEP_MODE, 0x0) != HAL_OK) {
+ ErrorNumber++;
+ }
+
+ HAL_Delay(120);
+
+ /* De-initialize DSI */
+ if (HAL_DSI_DeInit(&hlcd_dsi) != HAL_OK) {
+ ErrorNumber++;
+ }
+#if (USE_HAL_DSI_REGISTER_CALLBACKS == 0)
+ DSI_MspDeInit(&hlcd_dsi);
+#endif /* (USE_HAL_DSI_REGISTER_CALLBACKS == 0) */
+
+ /* De-initialize LTDC */
+ if (HAL_LTDC_DeInit(&hlcd_ltdc) != HAL_OK) {
+ ErrorNumber++;
+ }
+#if (USE_HAL_LTDC_REGISTER_CALLBACKS == 0)
+ LTDC_MspDeInit(&hlcd_ltdc);
+#endif /* (USE_HAL_LTDC_REGISTER_CALLBACKS == 0) */
+
+ /* De-initialize GFXMMU */
+ if (HAL_GFXMMU_DeInit(&hlcd_gfxmmu) != HAL_OK) {
+ ErrorNumber++;
+ }
+#if (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0)
+ GFXMMU_MspDeInit(&hlcd_gfxmmu);
+#endif /* (USE_HAL_GFXMMU_REGISTER_CALLBACKS == 0) */
+
+ if (ErrorNumber != 0U) {
+ status = BSP_ERROR_PERIPH_FAILURE;
+ }
+
+ return status;
+}
+
+/**
+ * @brief Initialize GFXMMU MSP.
+ * @param hgfxmmu GFXMMU handle
+ * @retval None
+ */
+static void GFXMMU_MspInit(GFXMMU_HandleTypeDef *hgfxmmu) {
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(hgfxmmu);
+
+ /* GFXMMU clock enable */
+ __HAL_RCC_GFXMMU_CLK_ENABLE();
+
+ /* Enable GFXMMU interrupt */
+ HAL_NVIC_SetPriority(GFXMMU_IRQn, BSP_LCD_GFXMMU_IT_PRIORITY, 0);
+ HAL_NVIC_EnableIRQ(GFXMMU_IRQn);
+}
+
+/**
+ * @brief De-Initialize GFXMMU MSP.
+ * @param hgfxmmu GFXMMU handle
+ * @retval None
+ */
+static void GFXMMU_MspDeInit(GFXMMU_HandleTypeDef *hgfxmmu) {
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(hgfxmmu);
+
+ /* Disable GFXMMU interrupt */
+ HAL_NVIC_DisableIRQ(GFXMMU_IRQn);
+
+ /* GFXMMU clock disable */
+ __HAL_RCC_GFXMMU_CLK_DISABLE();
+}
+
+/**
+ * @brief Initialize LTDC MSP.
+ * @param hltdc LTDC handle
+ * @retval None
+ */
+static void LTDC_MspInit(LTDC_HandleTypeDef *hltdc) {
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(hltdc);
+
+ /* Enable LCD clock */
+ __HAL_RCC_LTDC_CLK_ENABLE();
+
+ /* Enable LTDC interrupt */
+ HAL_NVIC_SetPriority(LTDC_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0);
+ HAL_NVIC_EnableIRQ(LTDC_IRQn);
+
+ HAL_NVIC_SetPriority(LTDC_ER_IRQn, BSP_LCD_LTDC_IT_PRIORITY, 0);
+ HAL_NVIC_EnableIRQ(LTDC_ER_IRQn);
+}
+
+/**
+ * @brief De-Initialize LTDC MSP.
+ * @param hltdc LTDC handle
+ * @retval None
+ */
+static void LTDC_MspDeInit(LTDC_HandleTypeDef *hltdc) {
+ /* Prevent unused argument(s) compilation warning */
+ UNUSED(hltdc);
+
+ /* Disable LTDC interrupts */
+ HAL_NVIC_DisableIRQ(LTDC_ER_IRQn);
+ HAL_NVIC_DisableIRQ(LTDC_IRQn);
+
+ /* LTDC clock disable */
+ __HAL_RCC_LTDC_CLK_DISABLE();
+}
+
+/**
+ * @brief Initialize DSI MSP.
+ * @param hdsi DSI handle
+ * @retval None
+ */
+static void DSI_MspInit(DSI_HandleTypeDef *hdsi) {
+ RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0};
+ RCC_PeriphCLKInitTypeDef DSIPHYInitPeriph = {0};
+ GPIO_InitTypeDef GPIO_InitStruct = {0};
+
+ UNUSED(hdsi);
+
+ /* Enable GPIOI & GPIOD clocks */
+ __HAL_RCC_GPIOD_CLK_ENABLE();
+ __HAL_RCC_GPIOI_CLK_ENABLE();
+
+ /* Configure DSI Reset pin */
+ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
+ GPIO_InitStruct.Pull = GPIO_PULLDOWN;
+ GPIO_InitStruct.Pin = GPIO_PIN_5;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+
+ /* Configure LCD Backlight Pin */
+ GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
+ GPIO_InitStruct.Pull = GPIO_PULLUP;
+ GPIO_InitStruct.Pin = GPIO_PIN_6;
+ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
+ HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
+
+ /* Enable DSI clock */
+ __HAL_RCC_DSI_CLK_ENABLE();
+
+ /** ################ Set DSI clock to D-PHY source clock ##################
+ * **/
+
+ /* Start and configurre PLL3 */
+ /* HSE = 16MHZ */
+ /* 16/(M=4) = 4MHz input (min) */
+ /* 4*(N=125) = 500MHz VCO (almost max) */
+ /* 500/(P=8) = 62.5 for DSI ie exactly the lane byte clock*/
+
+ PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI;
+ PLL3InitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_PLL3;
+ PLL3InitPeriph.PLL3.PLL3M = 4;
+ PLL3InitPeriph.PLL3.PLL3N = 125;
+ PLL3InitPeriph.PLL3.PLL3P = 8;
+ PLL3InitPeriph.PLL3.PLL3Q = 8;
+ PLL3InitPeriph.PLL3.PLL3R = 24;
+ PLL3InitPeriph.PLL3.PLL3FRACN = 0;
+ PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1;
+ PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP;
+ PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
+ (void)HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph);
+
+ __HAL_RCC_DSI_CLK_ENABLE();
+
+ /* Switch to D-PHY source clock */
+ /* Enable the DSI host */
+ hlcd_dsi.Instance = DSI;
+
+ __HAL_DSI_ENABLE(&hlcd_dsi);
+
+ /* Enable the DSI PLL */
+ __HAL_DSI_PLL_ENABLE(&hlcd_dsi);
+
+ HAL_Delay(1);
+
+ /* Enable the clock lane and the digital section of the D-PHY */
+ hlcd_dsi.Instance->PCTLR |= (DSI_PCTLR_CKE | DSI_PCTLR_DEN);
+
+ /* Set the TX escape clock division factor */
+ hlcd_dsi.Instance->CCR = 4;
+
+ HAL_Delay(1);
+
+ /* Config DSI Clock to DSI PHY */
+ DSIPHYInitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI;
+ DSIPHYInitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_DSIPHY;
+
+ (void)HAL_RCCEx_PeriphCLKConfig(&DSIPHYInitPeriph);
+
+ /* Reset */
+ HAL_Delay(11);
+ HAL_GPIO_WritePin(GPIOD, GPIO_PIN_5, GPIO_PIN_SET);
+ HAL_Delay(150);
+
+ /* Reset the TX escape clock division factor */
+ hlcd_dsi.Instance->CCR &= ~DSI_CCR_TXECKDIV;
+
+ /* Disable the DSI PLL */
+ __HAL_DSI_PLL_DISABLE(&hlcd_dsi);
+
+ /* Disable the DSI host */
+ __HAL_DSI_DISABLE(&hlcd_dsi);
+
+ /** #########################################################################
+ * **/
+
+ /* Enable DSI NVIC interrupt */
+ /* Default is lowest priority level */
+ HAL_NVIC_SetPriority(DSI_IRQn, 0x0FUL, 0);
+ HAL_NVIC_EnableIRQ(DSI_IRQn);
+}
+
+/**
+ * @brief De-Initialize DSI MSP.
+ * @param hdsi DSI handle
+ * @retval None
+ */
+static void DSI_MspDeInit(DSI_HandleTypeDef *hdsi) {
+ RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0};
+
+ UNUSED(hdsi);
+
+ /* Switch to PLL3 before Disable */
+ PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI;
+ PLL3InitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_PLL3;
+ PLL3InitPeriph.PLL3.PLL3M = 4;
+ PLL3InitPeriph.PLL3.PLL3N = 125;
+ PLL3InitPeriph.PLL3.PLL3P = 8;
+ PLL3InitPeriph.PLL3.PLL3Q = 8;
+ PLL3InitPeriph.PLL3.PLL3R = 24;
+ PLL3InitPeriph.PLL3.PLL3FRACN = 0;
+ PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_1;
+ PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP;
+ PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
+ (void)HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph);
+
+ /* DSI clock disable */
+ __HAL_RCC_DSI_CLK_DISABLE();
+
+ /** @brief Toggle Sw reset of DSI IP */
+ __HAL_RCC_DSI_FORCE_RESET();
+ __HAL_RCC_DSI_RELEASE_RESET();
+
+ /* Disable DSI interrupts */
+ HAL_NVIC_DisableIRQ(DSI_IRQn);
+}
+
+int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr) {
+ int32_t status = BSP_ERROR_NONE;
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ MX_LTDC_ConfigLayer(&hlcd_ltdc, 0, fb_addr);
+ }
+
+ return status;
+}
+
+int32_t BSP_LCD_Reinit(uint32_t Instance) {
+ int32_t status = BSP_ERROR_NONE;
+ if (Instance >= LCD_INSTANCES_NBR) {
+ status = BSP_ERROR_WRONG_PARAM;
+ } else {
+ // Switch to D-PHY source clock
+ // Enable the DSI host
+ hlcd_dsi.Instance = DSI;
+
+ MX_GFXMMU_Reinit(&hlcd_gfxmmu);
+ MX_DSI_Reinit(&hlcd_dsi);
+ MX_LTDC_Reinit(&hlcd_ltdc);
+ }
+
+ return status;
+}
diff --git a/core/embed/trezorhal/stm32u5/display/vg-2864 b/core/embed/trezorhal/stm32u5/display/vg-2864
new file mode 120000
index 000000000..88c9a8fad
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/display/vg-2864
@@ -0,0 +1 @@
+../../stm32f4/display/vg-2864
\ No newline at end of file
diff --git a/core/embed/trezorhal/stm32u5/displays/dsi.h b/core/embed/trezorhal/stm32u5/displays/dsi.h
index a717e4bb7..913adb369 100644
--- a/core/embed/trezorhal/stm32u5/displays/dsi.h
+++ b/core/embed/trezorhal/stm32u5/displays/dsi.h
@@ -3,10 +3,6 @@
#include STM32_HAL_H
-#define MAX_DISPLAY_RESX 240
-#define MAX_DISPLAY_RESY 240
-#define DISPLAY_RESX 240
-#define DISPLAY_RESY 240
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888
#define DISPLAY_FRAMEBUFFER_WIDTH 768
#define DISPLAY_FRAMEBUFFER_HEIGHT 480
diff --git a/core/embed/trezorhal/stm32u5/dma2d_gl.c b/core/embed/trezorhal/stm32u5/dma2d_gl.c
new file mode 120000
index 000000000..84c2c932d
--- /dev/null
+++ b/core/embed/trezorhal/stm32u5/dma2d_gl.c
@@ -0,0 +1 @@
+../stm32f4/dma2d_gl.c
\ No newline at end of file
diff --git a/core/embed/trezorhal/unix/display_driver.c b/core/embed/trezorhal/unix/display_driver.c
new file mode 100644
index 000000000..7f2946aea
--- /dev/null
+++ b/core/embed/trezorhal/unix/display_driver.c
@@ -0,0 +1,409 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#define _GNU_SOURCE
+
+#include
+
+#include
+#include
+
+#include "common.h"
+#include "profile.h"
+
+#define EMULATOR_BORDER 16
+
+#if defined TREZOR_MODEL_T
+
+#ifdef TREZOR_EMULATOR_RASPI
+#define WINDOW_WIDTH 480
+#define WINDOW_HEIGHT 320
+#define TOUCH_OFFSET_X 110
+#define TOUCH_OFFSET_Y 40
+#else
+#define WINDOW_WIDTH 400
+#define WINDOW_HEIGHT 600
+#define TOUCH_OFFSET_X 80
+#define TOUCH_OFFSET_Y 110
+#endif
+
+#elif defined TREZOR_MODEL_1
+
+#define WINDOW_WIDTH 200
+#define WINDOW_HEIGHT 340
+#define TOUCH_OFFSET_X 36
+#define TOUCH_OFFSET_Y 92
+
+#elif defined TREZOR_MODEL_R
+
+#define WINDOW_WIDTH 193
+#define WINDOW_HEIGHT 339
+#define TOUCH_OFFSET_X 32
+#define TOUCH_OFFSET_Y 84
+
+#elif defined TREZOR_MODEL_T3T1
+
+#define WINDOW_WIDTH 400
+#define WINDOW_HEIGHT 600
+#define TOUCH_OFFSET_X 80
+#define TOUCH_OFFSET_Y 110
+
+#else
+#error Unknown Trezor model
+#endif
+
+typedef struct {
+ // Current display orientation (0 or 180)
+ int orientation_angle;
+ // Current backlight level ranging from 0 to 255
+ int backlight_level;
+
+ SDL_Window *window;
+ SDL_Renderer *renderer;
+ SDL_Surface *buffer;
+ SDL_Texture *texture;
+ SDL_Texture *background;
+ SDL_Surface *prev_saved;
+
+#if DISPLAY_MONO
+ // SDL2 does not support 8bit surface/texture
+ // and we have to simulate it
+ uint8_t mono_framebuf[DISPLAY_RESX * DISPLAY_RESY];
+#endif
+
+} display_driver_t;
+
+static display_driver_t g_display_driver;
+
+//!@# TODO get rid of this...
+int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY;
+int sdl_touch_offset_x, sdl_touch_offset_y;
+
+void display_deinit(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ SDL_FreeSurface(drv->prev_saved);
+ SDL_FreeSurface(drv->buffer);
+ if (drv->background != NULL) {
+ SDL_DestroyTexture(drv->background);
+ }
+ if (drv->texture != NULL) {
+ SDL_DestroyTexture(drv->texture);
+ }
+ if (drv->renderer != NULL) {
+ SDL_DestroyRenderer(drv->renderer);
+ }
+ if (drv->window != NULL) {
+ SDL_DestroyWindow(drv->window);
+ }
+ SDL_Quit();
+}
+
+void display_init(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ if (SDL_Init(SDL_INIT_VIDEO) != 0) {
+ printf("%s\n", SDL_GetError());
+ ensure(secfalse, "SDL_Init error");
+ }
+ atexit(display_deinit);
+
+ char *window_title = NULL;
+ char *window_title_alloc = NULL;
+ if (asprintf(&window_title_alloc, "Trezor^emu: %s", profile_name()) > 0) {
+ window_title = window_title_alloc;
+ } else {
+ window_title = "Trezor^emu";
+ window_title_alloc = NULL;
+ }
+
+ drv->window =
+ SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT,
+#ifdef TREZOR_EMULATOR_RASPI
+ SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
+#else
+ SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
+#endif
+ );
+ free(window_title_alloc);
+ if (!drv->window) {
+ printf("%s\n", SDL_GetError());
+ ensure(secfalse, "SDL_CreateWindow error");
+ }
+ drv->renderer = SDL_CreateRenderer(drv->window, -1, SDL_RENDERER_SOFTWARE);
+ if (!drv->renderer) {
+ printf("%s\n", SDL_GetError());
+ SDL_DestroyWindow(drv->window);
+ ensure(secfalse, "SDL_CreateRenderer error");
+ }
+ SDL_SetRenderDrawColor(drv->renderer, 0, 0, 0, 255);
+ SDL_RenderClear(drv->renderer);
+
+ drv->buffer = SDL_CreateRGBSurface(0, DISPLAY_RESX, DISPLAY_RESY, 16, 0xF800,
+ 0x07E0, 0x001F, 0x0000);
+ drv->texture = SDL_CreateTexture(drv->renderer, SDL_PIXELFORMAT_RGB565,
+ SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX,
+ DISPLAY_RESY);
+ SDL_SetTextureBlendMode(drv->texture, SDL_BLENDMODE_BLEND);
+#ifdef __APPLE__
+ // macOS Mojave SDL black screen workaround
+ SDL_PumpEvents();
+ SDL_SetWindowSize(WINDOW, WINDOW_WIDTH, WINDOW_HEIGHT);
+#endif
+#ifdef TREZOR_EMULATOR_RASPI
+#include "background_raspi.h"
+ drv->background = IMG_LoadTexture_RW(
+ drv->renderer,
+ SDL_RWFromMem(background_raspi_jpg, background_raspi_jpg_len), 0);
+#else
+#if defined TREZOR_MODEL_T
+#include "background_T.h"
+ drv->background = IMG_LoadTexture_RW(
+ drv->renderer, SDL_RWFromMem(background_T_jpg, background_T_jpg_len), 0);
+#elif defined TREZOR_MODEL_1
+#include "background_1.h"
+ drv->background = IMG_LoadTexture_RW(
+ drv->renderer, SDL_RWFromMem(background_1_jpg, background_1_jpg_len), 0);
+#elif defined TREZOR_MODEL_R
+#include "background_T2B1.h"
+ drv->background = IMG_LoadTexture_RW(
+ drv->renderer,
+ SDL_RWFromMem(background_T2B1_png, background_T2B1_png_len), 0);
+#endif
+#endif
+ if (drv->background) {
+ SDL_SetTextureBlendMode(drv->background, SDL_BLENDMODE_NONE);
+ sdl_touch_offset_x = TOUCH_OFFSET_X;
+ sdl_touch_offset_y = TOUCH_OFFSET_Y;
+ } else {
+ SDL_SetWindowSize(drv->window, DISPLAY_RESX + 2 * EMULATOR_BORDER,
+ DISPLAY_RESY + 2 * EMULATOR_BORDER);
+ sdl_touch_offset_x = EMULATOR_BORDER;
+ sdl_touch_offset_y = EMULATOR_BORDER;
+ }
+#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
+ // T1 and TR do not have backlight capabilities in hardware, so
+ // setting its value here for emulator to avoid
+ // calling any `set_backlight` functions
+ drv->backlight_level = 255;
+#else
+ drv->backlight_level = 0;
+#endif
+#ifdef TREZOR_EMULATOR_RASPI
+ drv->orientation_angle = 270;
+ SDL_ShowCursor(SDL_DISABLE);
+#else
+ drv->orientation_angle = 0;
+#endif
+}
+
+void display_reinit(void) {
+ // not used
+}
+
+void display_finish_actions(void) {
+ // not used
+}
+
+int display_set_backlight(int level) {
+ display_driver_t *drv = &g_display_driver;
+
+#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
+ level = 255;
+#endif
+
+ if (drv->backlight_level != level && level >= 0 && level <= 255) {
+ drv->backlight_level = level;
+ display_refresh();
+ }
+
+ return drv->backlight_level;
+}
+
+int display_get_backlight(void) {
+ display_driver_t *drv = &g_display_driver;
+ return drv->backlight_level;
+}
+
+int display_set_orientation(int angle) {
+ display_driver_t *drv = &g_display_driver;
+ if (angle != drv->orientation_angle) {
+#if defined TREZOR_MODEL_T || defined TREZOR_MODEL_T3T1
+ if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
+#elif defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
+ if (angle == 0 || angle == 180) {
+#else
+#error Unknown Trezor model
+#endif
+ drv->orientation_angle = angle;
+ display_refresh();
+ }
+ }
+ return drv->orientation_angle;
+}
+
+int display_get_orientation(void) {
+ display_driver_t *drv = &g_display_driver;
+ return drv->orientation_angle;
+}
+
+#ifdef XFRAMEBUFFER
+void *display_get_frame_addr(void) {
+ display_driver_t *drv = &g_display_driver;
+
+#ifdef DISPLAY_MONO
+ return drv->mono_framebuf;
+#else
+ // !@# pitch???
+ return drv->buffer->pixels;
+#endif
+}
+
+#else // XFRAMEBUFFER
+
+void display_wait_for_sync(void) {
+ // not used
+}
+#endif
+
+#ifdef DISPLAY_MONO
+// Copies driver's monochromatic framebuffer into the RGB framebuffer used by
+// SDL
+void copy_mono_framebuf(display_driver_t *drv) {
+ for (int y = 0; y < DISPLAY_RESY; y++) {
+ uint16_t *dst =
+ (uint16_t *)((uint8_t *)drv->buffer->pixels + drv->buffer->pitch * y);
+ uint8_t *src = &drv->mono_framebuf[y * DISPLAY_RESX];
+ for (int x = 0; x < DISPLAY_RESX; x++) {
+ uint8_t lum = src[x];
+ dst[x] = gl_color16_rgb(lum, lum, lum);
+ }
+ }
+}
+#endif
+
+void display_refresh(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ if (!drv->renderer) {
+ display_init();
+ }
+
+#ifdef DISPLAY_MONO
+ copy_mono_framebuf(drv);
+#endif
+
+ if (drv->background) {
+ const SDL_Rect r = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
+ SDL_RenderCopy(drv->renderer, drv->background, NULL, &r);
+ } else {
+ SDL_RenderClear(drv->renderer);
+ }
+ // Show the display buffer
+ SDL_UpdateTexture(drv->texture, NULL, drv->buffer->pixels,
+ drv->buffer->pitch);
+#define BACKLIGHT_NORMAL 150
+ SDL_SetTextureAlphaMod(
+ drv->texture, MIN(255, 255 * drv->backlight_level / BACKLIGHT_NORMAL));
+ if (drv->background) {
+ const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX,
+ DISPLAY_RESY};
+ SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r,
+ drv->orientation_angle, NULL, 0);
+ } else {
+ const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX,
+ DISPLAY_RESY};
+ SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r,
+ drv->orientation_angle, NULL, 0);
+ }
+ SDL_RenderPresent(drv->renderer);
+}
+
+void display_set_compatible_settings(void) {
+ // not used
+}
+
+void display_fill(const dma2d_params_t *dp) {
+ display_driver_t *drv = &g_display_driver;
+
+ dma2d_params_t dp_new = *dp;
+ dp_new.dst_row =
+ (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * dp_new.dst_y);
+ dp_new.dst_stride = drv->buffer->pitch;
+
+ rgb565_fill(&dp_new);
+}
+
+void display_copy_rgb565(const dma2d_params_t *dp) {
+ display_driver_t *drv = &g_display_driver;
+
+ dma2d_params_t dp_new = *dp;
+ dp_new.dst_row =
+ (uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * dp_new.dst_y);
+ dp_new.dst_stride = drv->buffer->pitch;
+
+ rgb565_copy_rgb565(&dp_new);
+}
+
+void display_copy_mono4(const dma2d_params_t *dp) {
+ // !@# TODO
+}
+
+void display_copy_mono1p(const dma2d_params_t *dp) {
+ // !@# TODO
+}
+
+const char *display_save(const char *prefix) {
+ display_driver_t *drv = &g_display_driver;
+
+ if (!drv->renderer) {
+ display_init();
+ }
+ static int count;
+ static char filename[256];
+ // take a cropped view of the screen contents
+ const SDL_Rect rect = {0, 0, DISPLAY_RESX, DISPLAY_RESY};
+ SDL_Surface *crop = SDL_CreateRGBSurface(
+ drv->buffer->flags, rect.w, rect.h, drv->buffer->format->BitsPerPixel,
+ drv->buffer->format->Rmask, drv->buffer->format->Gmask,
+ drv->buffer->format->Bmask, drv->buffer->format->Amask);
+ SDL_BlitSurface(drv->buffer, &rect, crop, NULL);
+ // compare with previous screen, skip if equal
+ if (drv->prev_saved != NULL) {
+ if (memcmp(drv->prev_saved->pixels, crop->pixels, crop->pitch * crop->h) ==
+ 0) {
+ SDL_FreeSurface(crop);
+ return filename;
+ }
+ SDL_FreeSurface(drv->prev_saved);
+ }
+ // save to png
+ snprintf(filename, sizeof(filename), "%s%08d.png", prefix, count++);
+ IMG_SavePNG(crop, filename);
+ drv->prev_saved = crop;
+ return filename;
+}
+
+void display_clear_save(void) {
+ display_driver_t *drv = &g_display_driver;
+
+ SDL_FreeSurface(drv->prev_saved);
+ drv->prev_saved = NULL;
+}
diff --git a/core/embed/trezorhal/xdisplay.h b/core/embed/trezorhal/xdisplay.h
new file mode 100644
index 000000000..a63f80956
--- /dev/null
+++ b/core/embed/trezorhal/xdisplay.h
@@ -0,0 +1,135 @@
+/*
+ * This file is part of the Trezor project, https://trezor.io/
+ *
+ * Copyright (c) SatoshiLabs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef TREZORHAL_XDISPLAY_H
+#define TREZORHAL_XDISPLAY_H
+
+#include
+#include "gl_dma2d.h"
+
+#include TREZOR_BOARD
+
+// This is a universal API for controlling different types of display
+// controllers.
+//
+// Currently, following displays displays are supported
+//
+// VG-2864KSWEG01 - OLED Mono / 128x64 pixels / SPI
+// - Model T1B1 / Model T2B1
+//
+// UG-2828SWIG01 - OLED Mono / 128x128 pixels / Parallel
+// - Early revisions of T2B1
+//
+// ST7789V - TFT RGB / 240x240 pixels / Parallel
+// - Model T2T1 / Model T3T1
+//
+// ILI9341 - TFT RGB / 320x240 pixels / Parallel / LTDC + SPI
+// - STM32F429I-DISC1 Discovery Board
+//
+// MIPI -
+// - STM32U5A9J-DK Discovery Board
+
+// Fully initializes the display controller.
+void display_init(void);
+
+// Called in application to reinitialize an already initialized display
+// controller without any distrubing visible effect (blinking, etc.).
+void display_reinit(void);
+
+// Waits for any backround operations (such as DMA copying)
+// and returns.
+//
+// The function provides a barrier when jumping between
+// boardloader/bootloader and firmware.
+void display_finish_actions(void);
+
+// Sets display backlight level ranging from 0 (off)..255 (maximum).
+//
+// The default backligt level is 0. Without settings it
+// to some higher value the displayed pixels are not visible.
+// Beware that his also applies to the emulator.
+//
+// Returns the set level (usually the same value or the
+// closest value to the `level` argument)
+int display_set_backlight(int level);
+
+// Gets current display level ranging from 0 (off)..255 (maximum).
+int display_get_backlight(void);
+
+// Sets the display orientation.
+//
+// May accept one of following values: 0, 90, 180, 270
+// but accepted values are model-dependent.
+// Default display orientation is always 0.
+//
+// Returns the set orientation
+int display_set_orientation(int angle);
+
+// Gets the display's current orientation
+//
+// Returned value is one of 0, 90, 180, 270.
+int display_get_orientation(void);
+
+#ifdef XFRAMEBUFFER
+// Provides pointer to the inactive (writeable) framebuffer.
+//
+// If framebuffer is not available yet due to display refreshing etc.,
+// the function may block until the buffer is ready to write.
+void *display_get_frame_addr(void);
+
+#else // XFRAMEBUFFER
+
+// Waits for the vertical synchronization pulse.
+//
+// Used for synchronization with the display refresh cycle
+// to achieve tearless UX if possible when not using a frame buffer.
+void display_wait_for_sync(void);
+#endif
+
+// Swaps the frame buffers
+//
+// The function waits for vertical synchronization and
+// swaps the active (currently displayed) and the inactive frame buffers.
+void display_refresh(void);
+
+//
+void display_set_compatible_settings(void);
+
+// Functions for drawing on the display
+// Fills a rectangle with a specified color
+void display_fill(const dma2d_params_t *dp);
+
+// Copies an RGB565 bitmap to a specified rectangle
+void display_copy_rgb565(const dma2d_params_t *dp);
+
+// Copies a MONO4 bitmap to a specified rectangle
+void display_copy_mono4(const dma2d_params_t *dp);
+
+// Copies a MONO1P bitmap to a specified rectangle
+void display_copy_mono1p(const dma2d_params_t *dp);
+
+// Save the screen content to a file.
+//
+// The function is available only on the emulator
+const char *display_save(const char *prefix);
+void display_clear_save(void);
+
+#include "xdisplay_legacy.h"
+
+#endif // TREZORHAL_XDISPLAY_H
\ No newline at end of file
diff --git a/core/embed/trezorhal/xdisplay_legacy.c b/core/embed/trezorhal/xdisplay_legacy.c
new file mode 100644
index 000000000..3725cdda3
--- /dev/null
+++ b/core/embed/trezorhal/xdisplay_legacy.c
@@ -0,0 +1,50 @@
+#include "xdisplay_legacy.h"
+#include "xdisplay.h"
+
+int display_orientation(int angle) {
+ if (angle >= 0) {
+ return display_set_orientation(angle);
+ } else {
+ return display_get_orientation();
+ }
+}
+
+int display_backlight(int level) {
+ if (level >= 0) {
+ return display_set_backlight(level);
+ } else {
+ return display_get_backlight();
+ }
+}
+
+void display_shift_window(uint16_t pixels){};
+
+uint16_t display_get_window_offset(void) { return 0; }
+
+void display_pixeldata_dirty(void) {}
+
+uint8_t *display_get_wr_addr(void) { return (uint8_t *)0; }
+
+void display_sync(void) {}
+
+void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {}
+
+void display_pixeldata(uint16_t c) {}
+
+uint32_t *display_get_fb_addr(void) {
+#ifdef XFRAMEBUFFER
+ return (uint32_t *)display_get_frame_addr();
+#else
+ return (uint32_t *)0;
+#endif
+}
+
+void display_offset(int set_xy[2], int *get_x, int *get_y) {
+ *get_x = 0;
+ *get_y = 0;
+}
+
+void display_clear(void) {}
+
+void display_text_render_buffer(const char *text, int textlen, int font,
+ buffer_text_t *buffer, int text_offset) {}
diff --git a/core/embed/trezorhal/xdisplay_legacy.h b/core/embed/trezorhal/xdisplay_legacy.h
new file mode 100644
index 000000000..8e330fb9d
--- /dev/null
+++ b/core/embed/trezorhal/xdisplay_legacy.h
@@ -0,0 +1,34 @@
+
+#ifndef TREZORHAL_DISPLAY_LEGACY_H
+#define TREZORHAL_DISPLAY_LEGACY_H
+
+#include
+#include
+
+#define DISPLAY_FRAMEBUFFER_WIDTH 768
+#define DISPLAY_FRAMEBUFFER_HEIGHT 480
+#define DISPLAY_FRAMEBUFFER_OFFSET_X 0
+#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0
+
+// Functions emulating legacy API
+//
+
+int display_orientation(int angle);
+int display_backlight(int level);
+void display_refresh(void);
+void display_shift_window(uint16_t pixels);
+uint16_t display_get_window_offset(void);
+void display_pixeldata_dirty(void);
+uint8_t* display_get_wr_addr(void);
+void display_sync(void);
+void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
+void display_pixeldata(uint16_t c);
+uint32_t* display_get_fb_addr(void);
+
+void display_clear(void);
+void display_text_render_buffer(const char* text, int textlen, int font,
+ buffer_text_t* buffer, int text_offset);
+
+#define PIXELDATA(c) display_pixeldata(c)
+
+#endif // TREZORHAL_DISPLAY_LEGACY_H
diff --git a/core/site_scons/boards/discovery.py b/core/site_scons/boards/discovery.py
index 8f0738429..b5d39ec64 100644
--- a/core/site_scons/boards/discovery.py
+++ b/core/site_scons/boards/discovery.py
@@ -36,9 +36,20 @@ def configure(
sources += [
"embed/models/model_D001_layout.c",
]
- sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
- sources += ["embed/trezorhal/stm32f4/displays/ili9341_spi.c"]
+
+ if "new_rendering" in features_wanted:
+ sources += [
+ "embed/trezorhal/xdisplay_legacy.c",
+ "embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_driver.c",
+ "embed/trezorhal/stm32f4/display/stm32f429i-disc1/display_ltdc.c",
+ "embed/trezorhal/stm32f4/display/stm32f429i-disc1/ili9341_spi.c",
+ ]
+ else:
+ sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
+ sources += ["embed/trezorhal/stm32f4/displays/ili9341_spi.c"]
+
sources += ["embed/trezorhal/stm32f4/dma2d.c"]
+ sources += ["embed/trezorhal/stm32f4/dma2d_gl.c"]
sources += [
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma2d.c"
]
@@ -51,6 +62,11 @@ def configure(
features_available.append("dma2d")
features_available.append("framebuffer")
+ if "new_rendering" in features_wanted:
+ defines += ["XFRAMEBUFFER"]
+ features_available.append("xframebuffer")
+ features_available.append("display_rgb565")
+
if "input" in features_wanted:
sources += ["embed/trezorhal/stm32f4/i2c.c"]
sources += ["embed/trezorhal/stm32f4/touch/stmpe811.c"]
@@ -71,4 +87,10 @@ def configure(
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
+ rust_defs = env.get("ENV")["RUST_INCLUDES"]
+ rust_defs += "-DFRAMEBUFFER;"
+ if "new_rendering" in features_wanted:
+ rust_defs += "-DXFRAMEBUFFER;"
+ env.get("ENV")["RUST_INCLUDES"] = rust_defs
+
return features_available
diff --git a/core/site_scons/boards/discovery2.py b/core/site_scons/boards/discovery2.py
index 5a7c2d32a..453b50f20 100644
--- a/core/site_scons/boards/discovery2.py
+++ b/core/site_scons/boards/discovery2.py
@@ -43,9 +43,18 @@ def configure(
sources += [
"embed/models/model_D002_layout.c",
]
- sources += [
- f"embed/trezorhal/stm32u5/displays/{display}",
- ]
+
+ if "new_rendering" in features_wanted:
+ sources += [
+ "embed/trezorhal/xdisplay_legacy.c",
+ "embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_driver.c",
+ "embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_fb.c",
+ "embed/trezorhal/stm32u5/display/stm32u5a9j-dk/display_ltdc_dsi.c",
+ ]
+ else:
+ sources += [
+ f"embed/trezorhal/stm32u5/displays/{display}",
+ ]
if "input" in features_wanted:
sources += [
@@ -85,11 +94,16 @@ def configure(
defines += ["USE_DMA2D", "FRAMEBUFFER", "FRAMEBUFFER32BIT"]
sources += [
"embed/trezorhal/stm32u5/dma2d.c",
+ "embed/trezorhal/stm32u5/dma2d_gl.c",
]
features_available.append("dma2d")
features_available.append("framebuffer")
features_available.append("framebuffer32bit")
+ if "new_rendering" in features_wanted:
+ features_available.append("xframebuffer")
+ features_available.append("display_rgba8888")
+
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
env.get("ENV")["LINKER_SCRIPT"] = linker_script
@@ -97,4 +111,10 @@ def configure(
defs = env.get("CPPDEFINES_IMPLICIT")
defs += ["__ARM_FEATURE_CMSE=3"]
+ rust_defs = env.get("ENV")["RUST_INCLUDES"]
+ rust_defs += "-DFRAMEBUFFER;"
+ if "new_rendering" in features_wanted:
+ rust_defs += "-DXFRAMEBUFFER;"
+ env.get("ENV")["RUST_INCLUDES"] = rust_defs
+
return features_available
diff --git a/core/site_scons/boards/trezor_r_v10.py b/core/site_scons/boards/trezor_r_v10.py
index 3abe63aec..566c1412d 100644
--- a/core/site_scons/boards/trezor_r_v10.py
+++ b/core/site_scons/boards/trezor_r_v10.py
@@ -17,6 +17,11 @@ def configure(
board = "trezor_r_v10.h"
display = "vg-2864ksweg01.c"
+ if "new_rendering" in features_wanted:
+ defines += ["XFRAMEBUFFER"]
+ features_available.append("xframebuffer")
+ features_available.append("display_mono")
+
mcu = "STM32F427xx"
stm32f4_common_files(env, defines, sources, paths)
@@ -36,7 +41,12 @@ def configure(
sources += [
"embed/models/model_T2B1_layout.c",
]
- sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
+
+ if "new_rendering" in features_wanted:
+ sources += ["embed/trezorhal/xdisplay_legacy.c"]
+ sources += ["embed/trezorhal/stm32f4/display/vg-2864/display_driver.c"]
+ else:
+ sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
sources += ["embed/trezorhal/stm32f4/i2c.c"]
@@ -77,4 +87,9 @@ def configure(
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
+ if "new_rendering" in features_wanted:
+ rust_defs = env.get("ENV")["RUST_INCLUDES"]
+ rust_defs += "-DXFRAMEBUFFER;"
+ env.get("ENV")["RUST_INCLUDES"] = rust_defs
+
return features_available
diff --git a/core/site_scons/boards/trezor_r_v3.py b/core/site_scons/boards/trezor_r_v3.py
index 25e2c9dec..f2565ede1 100644
--- a/core/site_scons/boards/trezor_r_v3.py
+++ b/core/site_scons/boards/trezor_r_v3.py
@@ -17,6 +17,11 @@ def configure(
board = "trezor_r_v3.h"
display = "ug-2828tswig01.c"
+ if "new_rendering" in features_wanted:
+ defines += ["XFRAMEBUFFER"]
+ features_available.append("xframebuffer")
+ features_available.append("display_mono")
+
mcu = "STM32F427xx"
stm32f4_common_files(env, defines, sources, paths)
@@ -36,7 +41,12 @@ def configure(
sources += [
"embed/models/model_T2B1_layout.c",
]
- sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
+
+ if "new_rendering" in features_wanted:
+ sources += ["embed/trezorhal/xdisplay_legacy.c"]
+ sources += ["embed/trezorhal/stm32f4/display/ug-2828/display_driver.c"]
+ else:
+ sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
if "input" in features_wanted:
sources += ["embed/trezorhal/stm32f4/button.c"]
@@ -64,4 +74,9 @@ def configure(
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
+ if "new_rendering" in features_wanted:
+ rust_defs = env.get("ENV")["RUST_INCLUDES"]
+ rust_defs += "-DXFRAMEBUFFER;"
+ env.get("ENV")["RUST_INCLUDES"] = rust_defs
+
return features_available
diff --git a/core/site_scons/boards/trezor_r_v4.py b/core/site_scons/boards/trezor_r_v4.py
index 63dab36fc..e3461e5ee 100644
--- a/core/site_scons/boards/trezor_r_v4.py
+++ b/core/site_scons/boards/trezor_r_v4.py
@@ -17,6 +17,11 @@ def configure(
board = "trezor_r_v4.h"
display = "vg-2864ksweg01.c"
+ if "new_rendering" in features_wanted:
+ defines += ["XFRAMEBUFFER"]
+ features_available.append("xframebuffer")
+ features_available.append("display_mono")
+
mcu = "STM32F427xx"
stm32f4_common_files(env, defines, sources, paths)
@@ -36,7 +41,12 @@ def configure(
sources += [
"embed/models/model_T2B1_layout.c",
]
- sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
+
+ if "new_rendering" in features_wanted:
+ sources += ["embed/trezorhal/xdisplay_legacy.c"]
+ sources += ["embed/trezorhal/stm32f4/display/vg-2864/display_driver.c"]
+ else:
+ sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
if "input" in features_wanted:
sources += ["embed/trezorhal/stm32f4/button.c"]
@@ -60,4 +70,9 @@ def configure(
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
+ if "new_rendering" in features_wanted:
+ rust_defs = env.get("ENV")["RUST_INCLUDES"]
+ rust_defs += "-DXFRAMEBUFFER;"
+ env.get("ENV")["RUST_INCLUDES"] = rust_defs
+
return features_available
diff --git a/core/site_scons/boards/trezor_r_v6.py b/core/site_scons/boards/trezor_r_v6.py
index 6fe8f3044..3444c4bb1 100644
--- a/core/site_scons/boards/trezor_r_v6.py
+++ b/core/site_scons/boards/trezor_r_v6.py
@@ -17,6 +17,11 @@ def configure(
board = "trezor_r_v6.h"
display = "vg-2864ksweg01.c"
+ if "new_rendering" in features_wanted:
+ defines += ["XFRAMEBUFFER"]
+ features_available.append("xframebuffer")
+ features_available.append("display_mono")
+
mcu = "STM32F427xx"
stm32f4_common_files(env, defines, sources, paths)
@@ -36,7 +41,12 @@ def configure(
sources += [
"embed/models/model_T2B1_layout.c",
]
- sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
+
+ if "new_rendering" in features_wanted:
+ sources += ["embed/trezorhal/xdisplay_legacy.c"]
+ sources += ["embed/trezorhal/stm32f4/display/vg-2864/display_driver.c"]
+ else:
+ sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
if "input" in features_wanted:
sources += ["embed/trezorhal/stm32f4/button.c"]
@@ -60,4 +70,9 @@ def configure(
env.get("ENV")["TREZOR_BOARD"] = board
env.get("ENV")["MCU_TYPE"] = mcu
+ if "new_rendering" in features_wanted:
+ rust_defs = env.get("ENV")["RUST_INCLUDES"]
+ rust_defs += "-DXFRAMEBUFFER;"
+ env.get("ENV")["RUST_INCLUDES"] = rust_defs
+
return features_available
diff --git a/core/site_scons/boards/trezor_t.py b/core/site_scons/boards/trezor_t.py
index b53cd2c45..84bc0a69e 100644
--- a/core/site_scons/boards/trezor_t.py
+++ b/core/site_scons/boards/trezor_t.py
@@ -18,6 +18,9 @@ def configure(
hw_revision = 0
features_available.append("disp_i8080_8bit_dw")
+ if "new_rendering" in features_wanted:
+ features_available.append("display_rgb565")
+
mcu = "STM32F427xx"
stm32f4_common_files(env, defines, sources, paths)
@@ -37,20 +40,41 @@ def configure(
sources += [
"embed/models/model_T2T1_layout.c",
]
- sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
+ if "new_rendering" in features_wanted:
+ sources += ["embed/trezorhal/xdisplay_legacy.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_fb.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_driver.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_io.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_panel.c"]
+ sources += [
+ "embed/trezorhal/stm32f4/display/st-7789/panels/tf15411a.c",
+ ]
+ sources += [
+ "embed/trezorhal/stm32f4/display/st-7789/panels/154a.c",
+ ]
+ sources += [
+ "embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2411.c",
+ ]
+ sources += [
+ "embed/trezorhal/stm32f4/display/st-7789/panels/lx154a2422.c",
+ ]
+
+ else:
+ sources += [f"embed/trezorhal/stm32f4/displays/{display}"]
+ sources += [
+ "embed/trezorhal/stm32f4/displays/panels/tf15411a.c",
+ ]
+ sources += [
+ "embed/trezorhal/stm32f4/displays/panels/154a.c",
+ ]
+ sources += [
+ "embed/trezorhal/stm32f4/displays/panels/lx154a2411.c",
+ ]
+ sources += [
+ "embed/trezorhal/stm32f4/displays/panels/lx154a2422.c",
+ ]
+
sources += ["embed/trezorhal/stm32f4/backlight_pwm.c"]
- sources += [
- "embed/trezorhal/stm32f4/displays/panels/tf15411a.c",
- ]
- sources += [
- "embed/trezorhal/stm32f4/displays/panels/154a.c",
- ]
- sources += [
- "embed/trezorhal/stm32f4/displays/panels/lx154a2411.c",
- ]
- sources += [
- "embed/trezorhal/stm32f4/displays/panels/lx154a2422.c",
- ]
features_available.append("backlight")
@@ -87,7 +111,7 @@ def configure(
if "dma2d" in features_wanted:
defines += ["USE_DMA2D"]
sources += ["embed/trezorhal/stm32f4/dma2d.c"]
- sources += ["embed/trezorhal/stm32f4/dma2d_gdc.c"]
+ sources += ["embed/trezorhal/stm32f4/dma2d_gl.c"]
sources += [
"vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma2d.c"
]
diff --git a/core/site_scons/boards/trezor_t3t1_revE.py b/core/site_scons/boards/trezor_t3t1_revE.py
index 2d6d2291d..b79428f43 100644
--- a/core/site_scons/boards/trezor_t3t1_revE.py
+++ b/core/site_scons/boards/trezor_t3t1_revE.py
@@ -20,6 +20,11 @@ def configure(
features_available.append("framebuffer")
defines += ["FRAMEBUFFER"]
+ if "new_rendering" in features_wanted:
+ features_available.append("xframebuffer")
+ features_available.append("display_rgb565")
+ defines += ["XFRAMEBUFFER"]
+
mcu = "STM32U585xx"
linker_script = "stm32u58"
@@ -40,11 +45,23 @@ def configure(
sources += [
"embed/models/model_T3T1_layout.c",
]
- sources += [f"embed/trezorhal/stm32u5/displays/{display}"]
+
+ if "new_rendering" in features_wanted:
+ sources += ["embed/trezorhal/xdisplay_legacy.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_fb.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_driver.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_io.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_panel.c"]
+ sources += [
+ "embed/trezorhal/stm32u5/display/st-7789/panels/lx154a2422.c",
+ ]
+ else:
+ sources += [f"embed/trezorhal/stm32u5/displays/{display}"]
+ sources += [
+ "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c",
+ ]
+
sources += ["embed/trezorhal/stm32u5/backlight_pwm.c"]
- sources += [
- "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c",
- ]
env_constraints = env.get("CONSTRAINTS")
if not (env_constraints and "limited_util_s" in env_constraints):
@@ -94,6 +111,7 @@ def configure(
if "dma2d" in features_wanted:
defines += ["USE_DMA2D"]
sources += ["embed/trezorhal/stm32u5/dma2d.c"]
+ sources += ["embed/trezorhal/stm32u5/dma2d_gl.c"]
features_available.append("dma2d")
if "optiga" in features_wanted:
@@ -114,6 +132,8 @@ def configure(
rust_defs = env.get("ENV")["RUST_INCLUDES"]
rust_defs += "-DFRAMEBUFFER;"
+ if "new_rendering" in features_wanted:
+ rust_defs += "-DXFRAMEBUFFER;"
env.get("ENV")["RUST_INCLUDES"] = rust_defs
return features_available
diff --git a/core/site_scons/boards/trezor_t3t1_v4.py b/core/site_scons/boards/trezor_t3t1_v4.py
index 7d66720da..a8f68a3e7 100644
--- a/core/site_scons/boards/trezor_t3t1_v4.py
+++ b/core/site_scons/boards/trezor_t3t1_v4.py
@@ -20,6 +20,11 @@ def configure(
features_available.append("framebuffer")
defines += ["FRAMEBUFFER"]
+ if "new_rendering" in features_wanted:
+ features_available.append("xframebuffer")
+ features_available.append("display_rgb565")
+ defines += ["XFRAMEBUFFER"]
+
mcu = "STM32U585xx"
linker_script = "stm32u58"
@@ -41,10 +46,24 @@ def configure(
"embed/models/model_T3T1_layout.c",
]
sources += [f"embed/trezorhal/stm32u5/displays/{display}"]
+
+ if "new_rendering" in features_wanted:
+ sources += ["embed/trezorhal/xdisplay_legacy.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_fb.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_driver.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_io.c"]
+ sources += ["embed/trezorhal/stm32f4/display/st-7789/display_panel.c"]
+ sources += [
+ "embed/trezorhal/stm32u5/display/st-7789/panels/lx154a2422.c",
+ ]
+
+ else:
+ sources += [f"embed/trezorhal/stm32u5/displays/{display}"]
+ sources += [
+ "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c",
+ ]
+
sources += ["embed/trezorhal/stm32u5/backlight_pwm.c"]
- sources += [
- "embed/trezorhal/stm32u5/displays/panels/lx154a2422.c",
- ]
env_constraints = env.get("CONSTRAINTS")
if not (env_constraints and "limited_util_s" in env_constraints):
@@ -94,6 +113,7 @@ def configure(
if "dma2d" in features_wanted:
defines += ["USE_DMA2D"]
sources += ["embed/trezorhal/stm32u5/dma2d.c"]
+ sources += ["embed/trezorhal/stm32u5/dma2d_gl.c"]
features_available.append("dma2d")
if "optiga" in features_wanted:
@@ -114,6 +134,8 @@ def configure(
rust_defs = env.get("ENV")["RUST_INCLUDES"]
rust_defs += "-DFRAMEBUFFER;"
+ if "new_rendering" in features_wanted:
+ rust_defs += "-DXFRAMEBUFFER;"
env.get("ENV")["RUST_INCLUDES"] = rust_defs
return features_available