WIP - drawlib - low level refactoring

pull/3662/head
cepetr 1 month ago
parent 174ab733ac
commit 472a8bebd2

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

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

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

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

@ -18,6 +18,8 @@
*/
#include "display.h"
#include "display_draw.h"
#include "fonts/fonts.h"
/// class Display:
/// """

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef GDC_BITMAP_H
#define GDC_BITMAP_H
#include "gdc_color.h"
#include "gdc_geom.h"
#include <stddef.h>
#include <stdint.h>
// 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

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

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

@ -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 <http://www.gnu.org/licenses/>.
*/
#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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
// ------------------------------------------------------------------------
// 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

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

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

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

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

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

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

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

@ -61,8 +61,8 @@ void display_clear(void) {
// set MADCTL first so that we can set the window correctly next
display_orientation(0);
// address the complete frame memory
display_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1);
for (uint32_t i = 0; i < MAX_DISPLAY_RESX * MAX_DISPLAY_RESY; i++) {
display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
// 2 bytes per pixel because we're using RGB 5-6-5 format
PIXELDATA(0x0000);
}

@ -17,33 +17,33 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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];
}

@ -17,13 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GDC_COLOR_H
#define GDC_COLOR_H
#ifndef GL_COLOR_H
#define GL_COLOR_H
#include <stdint.h>
#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

@ -17,7 +17,36 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "gdc_dma2d.h"
#ifndef GL_DMA2D_H
#define GL_DMA2D_H
#include <stdbool.h>
#include <stdint.h>
#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

@ -17,14 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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++) {

@ -17,8 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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);

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <display.h>
#include "display_draw.h"
#include "fonts/fonts.h"
#include "gl_draw.h"
typedef struct {
int16_t dst_x;
int16_t dst_y;
int16_t src_x;
int16_t src_y;
int16_t width;
int16_t height;
} gl_clip_t;
static inline gl_clip_t gl_clip(gl_rect_t dst, const gl_bitmap_t* bitmap) {
int16_t dst_x = dst.x0;
int16_t dst_y = dst.y0;
int16_t src_x = 0;
int16_t src_y = 0;
if (bitmap != NULL) {
src_x += bitmap->offset.x;
src_y += bitmap->offset.y;
// Normalize negative x-offset of bitmap
if (src_x < 0) {
dst_x -= src_x;
src_x = 0;
}
// Normalize negative y-offset of src bitmap
if (src_y < 0) {
dst_y -= src_y;
src_y = 0;
}
}
// Normalize negative top-left of destination rectangle
if (dst_x < 0) {
src_x -= dst_x;
dst_x = 0;
}
if (dst_y < 0) {
src_y -= dst_y;
dst_y = 0;
}
// Calculate dimension of effective rectangle
int16_t width = MIN(DISPLAY_RESX, dst.x1) - dst_x;
int16_t height = MIN(DISPLAY_RESY, dst.y1) - dst_y;
if (bitmap != NULL) {
width = MIN(width, bitmap->size.x - src_x);
height = MIN(height, bitmap->size.y - src_y);
}
gl_clip_t clip = {
.dst_x = dst_x,
.dst_y = dst_y,
.src_x = src_x,
.src_y = src_y,
.width = width,
.height = height,
};
return clip;
}
void gl_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) {}

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

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

@ -14,6 +14,10 @@ micropython = []
protobuf = ["micropython"]
ui = []
dma2d = []
xframebuffer = []
display_mono = []
display_rgb565 = []
display_rgba8888 = []
framebuffer = []
framebuffer32bit = []
ui_debug = []

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

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

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

@ -0,0 +1,12 @@
use crate::ui::{
display::Color,
geometry::Rect,
shape::{DirectRenderer, Mono8Canvas},
};
pub fn render_on_display<'a, F>(_clip: Option<Rect>, _bg_color: Option<Color>, _func: F)
where
F: FnOnce(&mut DirectRenderer<'_, 'a, Mono8Canvas<'a>>),
{
panic!("Not implemented")
}

@ -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<Rect>, bg_color: Option<Color>, 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::<u8>(),
)
};
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();
}
}

@ -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<Rect>, bg_color: Option<Color>, 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::<u16>(),
)
};
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();
}
}

@ -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<Rect>, bg_color: Option<Color>, 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::<u32>(),
)
};
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();
}
}

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

@ -13,7 +13,7 @@ use static_alloc::Bump;
pub fn render_on_display<'a, F>(clip: Option<Rect>, bg_color: Option<Color>, 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<Self> {
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();

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

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

@ -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<Rect>, bg_color: Option<Color>, 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();
}

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

@ -3,18 +3,16 @@
#define HSE_8MHZ
#define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 320
#define DISPLAY_RESX 240
#define DISPLAY_RESY 320
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
#define DISPLAY_LEGACY_HEADER "displays/ltdc.h"
#define USE_I2C 1
#define USE_TOUCH 1
#define USE_SDRAM 1
#define USE_RGB_COLORS 1
#include "displays/ltdc.h"
#define I2C_COUNT 1
#define I2C_INSTANCE_0 I2C3
#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C3_CLK_ENABLE

@ -11,7 +11,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

@ -5,7 +5,8 @@
#define USE_BUTTON 1
#include "displays/vg-2864ksweg01.h"
#define DISPLAY_RESX 128
#define DISPLAY_RESY 64
#define BTN_LEFT_PIN GPIO_PIN_5
#define BTN_LEFT_PORT GPIOC

@ -8,7 +8,9 @@
#define USE_I2C 1
#define USE_CONSUMPTION_MASK 1
#include "displays/vg-2864ksweg01.h"
#define DISPLAY_RESX 128
#define DISPLAY_RESY 64
#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h"
#define BTN_LEFT_PIN GPIO_PIN_10
#define BTN_LEFT_PORT GPIOC

@ -6,7 +6,9 @@
#define USE_BUTTON 1
#define USE_SBU 1
#include "displays/ug-2828tswig01.h"
#define DISPLAY_RESX 128
#define DISPLAY_RESY 128
#define DISPLAY_LEGACY_HEADER "displays/ug-2828tswig01.h"
#define BTN_LEFT_PIN GPIO_PIN_0
#define BTN_LEFT_PORT GPIOA

@ -6,7 +6,9 @@
#define USE_BUTTON 1
#define USE_SBU 1
#include "displays/vg-2864ksweg01.h"
#define DISPLAY_RESX 128
#define DISPLAY_RESY 64
#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h"
#define BTN_LEFT_PIN GPIO_PIN_5
#define BTN_LEFT_PORT GPIOC

@ -6,7 +6,9 @@
#define USE_BUTTON 1
#define USE_SBU 1
#include "displays/vg-2864ksweg01.h"
#define DISPLAY_RESX 128
#define DISPLAY_RESY 64
#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h"
#define BTN_LEFT_PIN GPIO_PIN_10
#define BTN_LEFT_PORT GPIOC

@ -3,9 +3,6 @@
#define HSE_8MHZ
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define USE_SD_CARD 1
#define USE_I2C 1
#define USE_TOUCH 1
@ -14,12 +11,14 @@
#define USE_BACKLIGHT 1
#define USE_DISP_I8080_8BIT_DW 1
#include "displays/panels/lx154a2422.h"
#include "displays/st7789v.h"
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
#define DISPLAY_LEGACY_HEADER "displays/st7789v.h"
#define DISPLAY_IDENTIFY 1
#define DISPLAY_TE_PORT GPIOD
#define DISPLAY_TE_PIN GPIO_PIN_12
#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords
#define BACKLIGHT_PWM_FREQ 10000
#define BACKLIGHT_PWM_TIM TIM1

@ -1,9 +1,6 @@
#ifndef _TREZOR_T3T1_H
#define _TREZOR_T3T1_H
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define VDD_1V8 1
#define 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

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

@ -20,11 +20,19 @@
#ifndef TREZORHAL_DISPLAY_H
#define TREZORHAL_DISPLAY_H
#if NEW_RENDERING
#include <xdisplay.h>
#else
#include <stdint.h>
#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

@ -20,10 +20,12 @@
#ifndef TREZORHAL_DMA2D_H
#define TREZORHAL_DMA2D_H
#include "../gdc/gdc_core.h"
#include <stdbool.h>
#include <stdint.h>
#include "common.h"
#include "gl_dma2d.h"
void dma2d_init(void);
void dma2d_setup_const(void);

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

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <xdisplay.h>
#include "display_fb.h"
#include "display_io.h"
#include "display_panel.h"
#include "backlight_pwm.h"
#include "supervise.h"
#ifndef BOARDLOADER
#include "bg_copy.h"
#endif
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240)
#error "Incompatible display resolution"
#endif
// Display driver context.
typedef struct {
// Current display orientation (0, 90, 180, 270)
int orientation_angle;
} display_driver_t;
// Display driver instance
static display_driver_t g_display_driver;
void display_init(void) {
display_driver_t* drv = &g_display_driver;
memset(drv, 0, sizeof(display_driver_t));
display_io_init_gpio();
display_io_init_fmc();
display_panel_init();
display_panel_set_little_endian();
backlight_pwm_init();
#ifdef XFRAMEBUFFER
display_io_init_te_interrupt();
#endif
}
void display_reinit(void) {
display_driver_t* drv = &g_display_driver;
memset(drv, 0, sizeof(display_driver_t));
// Reinitialize FMC to set correct timing
// We have to do this in reinit because boardloader is fixed.
display_io_init_fmc();
// Important for model T as this is not set in boardloader
display_panel_set_little_endian();
display_panel_init_gamma();
backlight_pwm_reinit();
#ifdef XFRAMEBUFFER
display_io_init_te_interrupt();
#endif
}
void display_finish_actions(void) {
// !@# 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);

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "display_fb.h"
#include "display_io.h"
#include "display_panel.h"
#include "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

@ -0,0 +1,46 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
#define TREZOR_HAL_DISPLAY_INTERNAL_H
#include TREZOR_BOARD
#include <stdint.h>
#ifdef XFRAMEBUFFER
// Size of the physical frame buffer in bytes
#define PHYSICAL_FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2)
// Physical frame buffers in internal SRAM memory
//
// Both frame buffers layes in the fixed addresses that
// are shared between bootloaders and the firmware.
extern uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
extern uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
// The current frame buffer selector at fixed memory address
//
// The variable address is shared between bootloaders and the firmware
extern uint32_t current_frame_buffer;
#endif // XFRAMEBUFFER
#endif // TREZOR_HAL_DISPLAY_INTERNAL_H

@ -0,0 +1,145 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include TREZOR_BOARD
#include STM32_HAL_H
#include "display_io.h"
#include "irq.h"
__IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS =
(__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE);
__IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS =
(__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE |
(DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN));
void display_io_init_gpio(void) {
// init peripherals
__HAL_RCC_GPIOE_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_FMC_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
// LCD_RST/PC14
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Pin = GPIO_PIN_14;
// default to keeping display in reset
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
#ifdef DISPLAY_TE_PIN
// LCD_FMARK (tearing effect)
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = 0;
GPIO_InitStructure.Pin = DISPLAY_TE_PIN;
HAL_GPIO_Init(DISPLAY_TE_PORT, &GPIO_InitStructure);
#endif
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
// LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1
GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
// LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
#ifdef USE_DISP_I8080_16BIT_DW
// LCD_D8/PE11 LCD_D9/PE12 LCD_D10/PE13 LCD_D11/PE14
GPIO_InitStructure.Pin =
GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
// LCD_D12/PE15
GPIO_InitStructure.Pin = GPIO_PIN_15;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
// LCD_D13/PD8 LCD_D14/PD9 LCD_D15/PD10
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
#endif
}
void display_io_init_fmc(void) {
// Reference UM1725 "Description of STM32F4 HAL and LL drivers",
// section 64.2.1 "How to use this driver"
SRAM_HandleTypeDef external_display_data_sram = {0};
external_display_data_sram.Instance = FMC_NORSRAM_DEVICE;
external_display_data_sram.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
#ifdef USE_DISP_I8080_16BIT_DW
external_display_data_sram.Init.MemoryDataWidth =
FMC_NORSRAM_MEM_BUS_WIDTH_16;
#elif USE_DISP_I8080_8BIT_DW
external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
#endif
external_display_data_sram.Init.BurstAccessMode =
FMC_BURST_ACCESS_MODE_DISABLE;
external_display_data_sram.Init.WaitSignalPolarity =
FMC_WAIT_SIGNAL_POLARITY_LOW;
external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
external_display_data_sram.Init.AsynchronousWait =
FMC_ASYNCHRONOUS_WAIT_DISABLE;
external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
external_display_data_sram.Init.ContinuousClock =
FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
// reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
FMC_NORSRAM_TimingTypeDef normal_mode_timing = {0};
normal_mode_timing.AddressSetupTime = 5;
normal_mode_timing.AddressHoldTime = 1; // don't care
normal_mode_timing.DataSetupTime = 6;
normal_mode_timing.BusTurnAroundDuration = 0; // don't care
normal_mode_timing.CLKDivision = 2; // don't care
normal_mode_timing.DataLatency = 2; // don't care
normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
}
#ifdef DISPLAY_TE_INTERRUPT_HANDLER
void display_io_init_te_interrupt(void) {
EXTI_HandleTypeDef EXTI_Handle = {0};
EXTI_ConfigTypeDef EXTI_Config = {0};
EXTI_Config.GPIOSel = DISPLAY_TE_INTERRUPT_GPIOSEL;
EXTI_Config.Line = DISPLAY_TE_INTERRUPT_EXTI_LINE;
EXTI_Config.Mode = EXTI_MODE_INTERRUPT;
EXTI_Config.Trigger = EXTI_TRIGGER_RISING;
HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config);
// setup interrupt for tearing effect pin
HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0);
}
#endif

@ -0,0 +1,67 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_DISPLAY_IO_H
#define TREZORHAL_DISPLAY_IO_H
#include STM32_HAL_H
#include TREZOR_BOARD
void display_io_init_gpio(void);
void display_io_init_fmc(void);
void display_io_init_te_interrupt(void);
#ifndef FMC_BANK1
#define FMC_BANK1 0x60000000U
#endif
#define DISPLAY_MEMORY_BASE FMC_BANK1
#define DISPLAY_MEMORY_PIN 16
#ifdef USE_DISP_I8080_16BIT_DW
#define DISPLAY_ADDR_SHIFT 2
#define DISP_MEM_TYPE uint16_t
#elif USE_DISP_I8080_8BIT_DW
#define DISPLAY_ADDR_SHIFT 1
#define DISP_MEM_TYPE uint8_t
#else
#error "Unsupported display interface"
#endif
/*#define DISPLAY_CMD_ADDRESS ((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE))
#define DISPLAY_DATA_ADDRESS \
((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE | \
(DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN)))
*/
extern __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS;
extern __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS;
#define ISSUE_CMD_BYTE(X) (*(DISPLAY_CMD_ADDRESS) = (X))
#define ISSUE_DATA_BYTE(X) (*(DISPLAY_DATA_ADDRESS) = (X))
#ifdef USE_DISP_I8080_16BIT_DW
#define ISSUE_PIXEL_DATA(X) DATA(X)
#elif USE_DISP_I8080_8BIT_DW
#define ISSUE_PIXEL_DATA(X) \
ISSUE_DATA_BYTE((X)&0xFF); \
ISSUE_DATA_BYTE((X) >> 8)
#endif
#endif // TREZORHAL_DISPLAY_IO_H

@ -0,0 +1,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 <http://www.gnu.org/licenses/>.
*/
// using const volatile instead of #define results in binaries that change
// only in 1-byte when the flag changes.
// using #define leads compiler to over-optimize the code leading to bigger
// differencies in the resulting binaries.
#include "display_panel.h"
#include "display_io.h"
#ifdef TREZOR_MODEL_T
#include "panels/154a.h"
#include "panels/lx154a2411.h"
#include "panels/lx154a2422.h"
#include "panels/tf15411a.h"
#else
#include "panels/lx154a2422.h"
#endif
// using const volatile instead of #define results in binaries that change
// only in 1-byte when the flag changes.
// using #define leads compiler to over-optimize the code leading to bigger
// differencies in the resulting binaries.
const volatile uint8_t DISPLAY_ST7789V_INVERT_COLORS2 = 1;
#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
}

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZORHAL_ST7789_PANEL_H
#define TREZORHAL_ST7789_PANEL_H
#include <stdbool.h>
#include <stdint.h>
// section "9.1.3 RDDID (04h): Read Display ID"
// of ST7789V datasheet
#define DISPLAY_ID_ST7789V 0x858552U
// section "6.2.1. Read display identification information (04h)"
// of GC9307 datasheet
#define DISPLAY_ID_GC9307 0x009307U
// section "8.3.23 Read ID4 (D3h)"
// of ILI9341V datasheet
#define DISPLAY_ID_ILI9341V 0x009341U
// Identifies the connected display panel and
// returns one of DISPLAY_ID_xxx constant
uint32_t display_panel_identify(void);
bool display_panel_is_inverted();
void display_panel_init(void);
void display_panel_init_gamma(void);
void display_panel_set_little_endian(void);
void display_panel_set_big_endian(void);
void display_panel_sleep(void);
void display_panel_unsleep(void);
void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
uint16_t y1);
void display_panel_rotate(int angle);
#endif // TREZORHAL_ST7789_PANEL_H

@ -0,0 +1,132 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../display_io.h"
void _154a_init_seq(void) {
// most recent manual: https://www.newhavendisplay.com/app_notes/ILI9341.pdf
// TEON: Tearing Effect Line On; V-blanking only
ISSUE_CMD_BYTE(0x35);
ISSUE_DATA_BYTE(0x00);
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
// input)
ISSUE_CMD_BYTE(0x3A);
ISSUE_DATA_BYTE(0x55);
// Display Function Control: gate scan direction 319 -> 0
ISSUE_CMD_BYTE(0xB6);
ISSUE_DATA_BYTE(0x0A);
ISSUE_DATA_BYTE(0xC2);
ISSUE_DATA_BYTE(0x27);
ISSUE_DATA_BYTE(0x00);
// Interface Control: XOR BGR as ST7789V does
ISSUE_CMD_BYTE(0xF6);
ISSUE_DATA_BYTE(0x09);
ISSUE_DATA_BYTE(0x30);
ISSUE_DATA_BYTE(0x00);
// the above config is the most important and definitely necessary
ISSUE_CMD_BYTE(0xCF);
ISSUE_DATA_BYTE(0x00);
ISSUE_DATA_BYTE(0xC1);
ISSUE_DATA_BYTE(0x30);
ISSUE_CMD_BYTE(0xED);
ISSUE_DATA_BYTE(0x64);
ISSUE_DATA_BYTE(0x03);
ISSUE_DATA_BYTE(0x12);
ISSUE_DATA_BYTE(0x81);
ISSUE_CMD_BYTE(0xE8);
ISSUE_DATA_BYTE(0x85);
ISSUE_DATA_BYTE(0x10);
ISSUE_DATA_BYTE(0x7A);
ISSUE_CMD_BYTE(0xF7);
ISSUE_DATA_BYTE(0x20);
ISSUE_CMD_BYTE(0xEA);
ISSUE_DATA_BYTE(0x00);
ISSUE_DATA_BYTE(0x00);
// power control VRH[5:0]
ISSUE_CMD_BYTE(0xC0);
ISSUE_DATA_BYTE(0x23);
// power control SAP[2:0] BT[3:0]
ISSUE_CMD_BYTE(0xC1);
ISSUE_DATA_BYTE(0x12);
// vcm control 1
ISSUE_CMD_BYTE(0xC5);
ISSUE_DATA_BYTE(0x60);
ISSUE_DATA_BYTE(0x44);
// vcm control 2
ISSUE_CMD_BYTE(0xC7);
ISSUE_DATA_BYTE(0x8A);
// framerate
ISSUE_CMD_BYTE(0xB1);
ISSUE_DATA_BYTE(0x00);
ISSUE_DATA_BYTE(0x18);
// 3 gamma func disable
ISSUE_CMD_BYTE(0xF2);
ISSUE_DATA_BYTE(0x00);
// gamma curve 1
ISSUE_CMD_BYTE(0xE0);
ISSUE_DATA_BYTE(0x0F);
ISSUE_DATA_BYTE(0x2F);
ISSUE_DATA_BYTE(0x2C);
ISSUE_DATA_BYTE(0x0B);
ISSUE_DATA_BYTE(0x0F);
ISSUE_DATA_BYTE(0x09);
ISSUE_DATA_BYTE(0x56);
ISSUE_DATA_BYTE(0xD9);
ISSUE_DATA_BYTE(0x4A);
ISSUE_DATA_BYTE(0x0B);
ISSUE_DATA_BYTE(0x14);
ISSUE_DATA_BYTE(0x05);
ISSUE_DATA_BYTE(0x0C);
ISSUE_DATA_BYTE(0x06);
ISSUE_DATA_BYTE(0x00);
// gamma curve 2
ISSUE_CMD_BYTE(0xE1);
ISSUE_DATA_BYTE(0x00);
ISSUE_DATA_BYTE(0x10);
ISSUE_DATA_BYTE(0x13);
ISSUE_DATA_BYTE(0x04);
ISSUE_DATA_BYTE(0x10);
ISSUE_DATA_BYTE(0x06);
ISSUE_DATA_BYTE(0x25);
ISSUE_DATA_BYTE(0x26);
ISSUE_DATA_BYTE(0x3B);
ISSUE_DATA_BYTE(0x04);
ISSUE_DATA_BYTE(0x0B);
ISSUE_DATA_BYTE(0x0A);
ISSUE_DATA_BYTE(0x33);
ISSUE_DATA_BYTE(0x39);
ISSUE_DATA_BYTE(0x0F);
}

@ -17,14 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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

@ -0,0 +1,82 @@
#include "../display_io.h"
void lx154a2411_gamma(void) {
// positive voltage correction
ISSUE_CMD_BYTE(0xE0);
ISSUE_DATA_BYTE(0xD0);
ISSUE_DATA_BYTE(0x03);
ISSUE_DATA_BYTE(0x08);
ISSUE_DATA_BYTE(0x0E);
ISSUE_DATA_BYTE(0x11);
ISSUE_DATA_BYTE(0x2B);
ISSUE_DATA_BYTE(0x3B);
ISSUE_DATA_BYTE(0x44);
ISSUE_DATA_BYTE(0x4C);
ISSUE_DATA_BYTE(0x2B);
ISSUE_DATA_BYTE(0x16);
ISSUE_DATA_BYTE(0x15);
ISSUE_DATA_BYTE(0x1E);
ISSUE_DATA_BYTE(0x21);
// negative voltage correction
ISSUE_CMD_BYTE(0xE1);
ISSUE_DATA_BYTE(0xD0);
ISSUE_DATA_BYTE(0x03);
ISSUE_DATA_BYTE(0x08);
ISSUE_DATA_BYTE(0x0E);
ISSUE_DATA_BYTE(0x11);
ISSUE_DATA_BYTE(0x2B);
ISSUE_DATA_BYTE(0x3B);
ISSUE_DATA_BYTE(0x54);
ISSUE_DATA_BYTE(0x4C);
ISSUE_DATA_BYTE(0x2B);
ISSUE_DATA_BYTE(0x16);
ISSUE_DATA_BYTE(0x15);
ISSUE_DATA_BYTE(0x1E);
ISSUE_DATA_BYTE(0x21);
}
void lx154a2411_init_seq(void) {
// most recent manual:
// https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf
// TEON: Tearing Effect Line On; V-blanking only
ISSUE_CMD_BYTE(0x35);
ISSUE_DATA_BYTE(0x00);
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
// input)
ISSUE_CMD_BYTE(0x3A);
ISSUE_DATA_BYTE(0x55);
// CMD2EN: Commands in command table 2 can be executed when EXTC level is Low
ISSUE_CMD_BYTE(0xDF);
ISSUE_DATA_BYTE(0x5A);
ISSUE_DATA_BYTE(0x69);
ISSUE_DATA_BYTE(0x02);
ISSUE_DATA_BYTE(0x01);
// LCMCTRL: LCM Control: XOR RGB setting
ISSUE_CMD_BYTE(0xC0);
ISSUE_DATA_BYTE(0x20);
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.;
// gate scan direction 319 -> 0
ISSUE_CMD_BYTE(0xE4);
ISSUE_DATA_BYTE(0x1D);
ISSUE_DATA_BYTE(0x0A);
ISSUE_DATA_BYTE(0x11);
// INVOFF (20h): Display Inversion Off
// INVON (21h): Display Inversion On
ISSUE_CMD_BYTE(0x20);
// the above config is the most important and definitely necessary
// PWCTRL1: Power Control 1
ISSUE_CMD_BYTE(0xD0);
ISSUE_DATA_BYTE(0xA4);
ISSUE_DATA_BYTE(0xA1);
lx154a2411_gamma();
}

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

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

@ -17,32 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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 <stddef.h>
#include <stdint.h>
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

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

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TF15411A_H_
#define TF15411A_H_
// GC9307 IC controller
void tf15411a_init_seq(void);
void tf15411a_rotate(int degrees);
#endif

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "display_internal.h"
#include "ili9341_spi.h"
#include "xdisplay.h"
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 320)
#error "Incompatible display resolution"
#endif
// Display driver context.
typedef struct {
// 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);
*/

@ -17,35 +17,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GDC_DMA2D_H
#define GDC_DMA2D_H
#ifndef TREZORHAL_DISPLAY_INTERNAL_H
#define TREZORHAL_DISPLAY_INTERNAL_H
#include <stdbool.h>
#include <stdint.h>
#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
#endif // TREZORHAL_DISPLAY_INTERNAL_H

@ -0,0 +1,291 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "display_internal.h"
#include "ili9341_spi.h"
#include "xdisplay.h"
#define MAX_LAYER_NUMBER 2
LTDC_HandleTypeDef LtdcHandler;
static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
/* Default LCD configuration with LCD Layer 1 */
uint32_t ActiveLayer = 0;
/**
* @brief Initializes the LCD layers.
* @param LayerIndex: the layer foreground or background.
* @param FB_Address: the layer frame buffer.
*/
void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
LTDC_LayerCfgTypeDef Layercfg;
/* Layer Init */
Layercfg.WindowX0 = 0;
Layercfg.WindowX1 = DISPLAY_RESX;
Layercfg.WindowY0 = 0;
Layercfg.WindowY1 = DISPLAY_RESY;
Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
Layercfg.FBStartAdress = FB_Address;
Layercfg.Alpha = 255;
Layercfg.Alpha0 = 0;
Layercfg.Backcolor.Blue = 0;
Layercfg.Backcolor.Green = 0;
Layercfg.Backcolor.Red = 0;
Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
Layercfg.ImageWidth = DISPLAY_RESX;
Layercfg.ImageHeight = DISPLAY_RESY;
HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex);
// DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE;
// DrawProp[LayerIndex].pFont = &Font24;
// DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK;
/* Dithering activation */
HAL_LTDC_EnableDither(&LtdcHandler);
}
/**
* @brief Selects the LCD Layer.
* @param LayerIndex: the Layer foreground or background.
*/
void BSP_LCD_SelectLayer(uint32_t LayerIndex) { ActiveLayer = LayerIndex; }
/**
* @brief Sets a LCD Layer visible.
* @param LayerIndex: the visible Layer.
* @param state: new state of the specified layer.
* This parameter can be: ENABLE or DISABLE.
*/
void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState state) {
if (state == ENABLE) {
__HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
} else {
__HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
}
__HAL_LTDC_RELOAD_CONFIG(&LtdcHandler);
}
/**
* @brief Sets an LCD Layer visible without reloading.
* @param LayerIndex: Visible Layer
* @param State: New state of the specified layer
* This parameter can be one of the following values:
* @arg ENABLE
* @arg DISABLE
* @retval None
*/
void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex,
FunctionalState State) {
if (State == ENABLE) {
__HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
} else {
__HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
}
/* Do not Sets the Reload */
}
/**
* @brief Configures the Transparency.
* @param LayerIndex: the Layer foreground or background.
* @param Transparency: the Transparency,
* This parameter must range from 0x00 to 0xFF.
*/
void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) {
HAL_LTDC_SetAlpha(&LtdcHandler, Transparency, LayerIndex);
}
/**
* @brief Configures the transparency without reloading.
* @param LayerIndex: Layer foreground or background.
* @param Transparency: Transparency
* This parameter must be a number between Min_Data = 0x00 and
* Max_Data = 0xFF
* @retval None
*/
void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex,
uint8_t Transparency) {
HAL_LTDC_SetAlpha_NoReload(&LtdcHandler, Transparency, LayerIndex);
}
/**
* @brief Sets a LCD layer frame buffer address.
* @param LayerIndex: specifies the Layer foreground or background
* @param Address: new LCD frame buffer value
*/
void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) {
HAL_LTDC_SetAddress(&LtdcHandler, Address, LayerIndex);
}
/**
* @brief Sets an LCD layer frame buffer address without reloading.
* @param LayerIndex: Layer foreground or background
* @param Address: New LCD frame buffer value
* @retval None
*/
void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) {
HAL_LTDC_SetAddress_NoReload(&LtdcHandler, Address, LayerIndex);
}
void BSP_LCD_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure = {0};
/* Enable the LTDC and DMA2D Clock */
__HAL_RCC_LTDC_CLK_ENABLE();
__HAL_RCC_DMA2D_CLK_ENABLE();
/* Enable GPIOs clock */
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
/* GPIOs Configuration */
/*
+------------------------+-----------------------+----------------------------+
+ LCD pins assignment +
+------------------------+-----------------------+----------------------------+
| LCD_TFT R2 <-> PC.10 | LCD_TFT G2 <-> PA.06 | LCD_TFT B2 <-> PD.06 | |
LCD_TFT R3 <-> PB.00 | LCD_TFT G3 <-> PG.10 | LCD_TFT B3 <-> PG.11 |
| LCD_TFT R4 <-> PA.11 | LCD_TFT G4 <-> PB.10 | LCD_TFT B4 <-> PG.12 | |
LCD_TFT R5 <-> PA.12 | LCD_TFT G5 <-> PB.11 | LCD_TFT B5 <-> PA.03 |
| LCD_TFT R6 <-> PB.01 | LCD_TFT G6 <-> PC.07 | LCD_TFT B6 <-> PB.08 | |
LCD_TFT R7 <-> PG.06 | LCD_TFT G7 <-> PD.03 | LCD_TFT B7 <-> PB.09 |
-------------------------------------------------------------------------------
| LCD_TFT HSYNC <-> PC.06 | LCDTFT VSYNC <-> PA.04 |
| LCD_TFT CLK <-> PG.07 | LCD_TFT DE <-> PF.10 |
-----------------------------------------------------
*/
/* GPIOA configuration */
GPIO_InitStructure.Pin =
GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_11 | GPIO_PIN_12;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
GPIO_InitStructure.Alternate = GPIO_AF14_LTDC;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
/* GPIOB configuration */
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
/* GPIOC configuration */
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10;
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
/* GPIOD configuration */
GPIO_InitStructure.Pin = GPIO_PIN_3 | GPIO_PIN_6;
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
/* GPIOF configuration */
GPIO_InitStructure.Pin = GPIO_PIN_10;
HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);
/* GPIOG configuration */
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_11;
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
/* GPIOB configuration */
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1;
GPIO_InitStructure.Alternate = GPIO_AF9_LTDC;
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
/* GPIOG configuration */
GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_12;
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
/* On STM32F429I-DISCO, it is not possible to read ILI9341 ID because */
/* PIN EXTC is not connected to VDD and then LCD_READ_ID4 is not accessible.
*/
/* In this case, ReadID function is bypassed.*/
/*if(ili9341_drv.ReadID() == ILI9341_ID)*/
/* LTDC Configuration ----------------------------------------------------*/
LtdcHandler.Instance = LTDC;
/* Timing configuration (Typical configuration from ILI9341 datasheet)
HSYNC=10 (9+1)
HBP=20 (29-10+1)
ActiveW=240 (269-20-10+1)
HFP=10 (279-240-20-10+1)
VSYNC=2 (1+1)
VBP=2 (3-2+1)
ActiveH=320 (323-2-2+1)
VFP=4 (327-320-2-2+1)
*/
/* Configure horizontal synchronization width */
LtdcHandler.Init.HorizontalSync = ILI9341_HSYNC;
/* Configure vertical synchronization height */
LtdcHandler.Init.VerticalSync = ILI9341_VSYNC;
/* Configure accumulated horizontal back porch */
LtdcHandler.Init.AccumulatedHBP = ILI9341_HBP;
/* Configure accumulated vertical back porch */
LtdcHandler.Init.AccumulatedVBP = ILI9341_VBP;
/* Configure accumulated active width */
LtdcHandler.Init.AccumulatedActiveW = 269;
/* Configure accumulated active height */
LtdcHandler.Init.AccumulatedActiveH = 323;
/* Configure total width */
LtdcHandler.Init.TotalWidth = 279;
/* Configure total height */
LtdcHandler.Init.TotalHeigh = 327;
/* Configure R,G,B component values for LCD background color */
LtdcHandler.Init.Backcolor.Red = 0;
LtdcHandler.Init.Backcolor.Blue = 0;
LtdcHandler.Init.Backcolor.Green = 0;
/* LCD clock configuration */
/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */
/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 Mhz */
/* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_8 = 48/4 = 6Mhz */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
PeriphClkInitStruct.PLLSAI.PLLSAIR = 4;
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
/* Polarity */
LtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL;
LtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL;
LtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL;
LtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
HAL_LTDC_Init(&LtdcHandler);
/* Initialize the LCD Layers */
BSP_LCD_LayerDefaultInit(1, FRAME_BUFFER_ADDR);
memset((void *)FRAME_BUFFER_ADDR, 0, FRAME_BUFFER_SIZE);
}

@ -0,0 +1,512 @@
#include <stdint.h>
#include TREZOR_BOARD
#include "ili9341_spi.h"
#include STM32_HAL_H
/**
* @brief ILI9341 chip IDs
*/
#define ILI9341_ID 0x9341
/**
* @brief ILI9341 Size
*/
#define ILI9341_LCD_PIXEL_WIDTH ((uint16_t)240)
#define ILI9341_LCD_PIXEL_HEIGHT ((uint16_t)320)
/**
* @brief ILI9341 Timing
*/
/* Timing configuration (Typical configuration from ILI9341 datasheet)
HSYNC=10 (9+1)
HBP=20 (29-10+1)
ActiveW=240 (269-20-10+1)
HFP=10 (279-240-20-10+1)
VSYNC=2 (1+1)
VBP=2 (3-2+1)
ActiveH=320 (323-2-2+1)
VFP=4 (327-320-2-2+1)
*/
/**
* @brief ILI9341 Registers
*/
/* Level 1 Commands */
#define LCD_SWRESET 0x01 /* Software Reset */
#define LCD_READ_DISPLAY_ID 0x04 /* Read display identification information */
#define LCD_RDDST 0x09 /* Read Display Status */
#define LCD_RDDPM 0x0A /* Read Display Power Mode */
#define LCD_RDDMADCTL 0x0B /* Read Display MADCTL */
#define LCD_RDDCOLMOD 0x0C /* Read Display Pixel Format */
#define LCD_RDDIM 0x0D /* Read Display Image Format */
#define LCD_RDDSM 0x0E /* Read Display Signal Mode */
#define LCD_RDDSDR 0x0F /* Read Display Self-Diagnostic Result */
#define LCD_SPLIN 0x10 /* Enter Sleep Mode */
#define LCD_SLEEP_OUT 0x11 /* Sleep out register */
#define LCD_PTLON 0x12 /* Partial Mode ON */
#define LCD_NORMAL_MODE_ON 0x13 /* Normal Display Mode ON */
#define LCD_DINVOFF 0x20 /* Display Inversion OFF */
#define LCD_DINVON 0x21 /* Display Inversion ON */
#define LCD_GAMMA 0x26 /* Gamma register */
#define LCD_DISPLAY_OFF 0x28 /* Display off register */
#define LCD_DISPLAY_ON 0x29 /* Display on register */
#define LCD_COLUMN_ADDR 0x2A /* Colomn address register */
#define LCD_PAGE_ADDR 0x2B /* Page address register */
#define LCD_GRAM 0x2C /* GRAM register */
#define LCD_RGBSET 0x2D /* Color SET */
#define LCD_RAMRD 0x2E /* Memory Read */
#define LCD_PLTAR 0x30 /* Partial Area */
#define LCD_VSCRDEF 0x33 /* Vertical Scrolling Definition */
#define LCD_TEOFF 0x34 /* Tearing Effect Line OFF */
#define LCD_TEON 0x35 /* Tearing Effect Line ON */
#define LCD_MAC 0x36 /* Memory Access Control register*/
#define LCD_VSCRSADD 0x37 /* Vertical Scrolling Start Address */
#define LCD_IDMOFF 0x38 /* Idle Mode OFF */
#define LCD_IDMON 0x39 /* Idle Mode ON */
#define LCD_PIXEL_FORMAT 0x3A /* Pixel Format register */
#define LCD_WRITE_MEM_CONTINUE 0x3C /* Write Memory Continue */
#define LCD_READ_MEM_CONTINUE 0x3E /* Read Memory Continue */
#define LCD_SET_TEAR_SCANLINE 0x44 /* Set Tear Scanline */
#define LCD_GET_SCANLINE 0x45 /* Get Scanline */
#define LCD_WDB 0x51 /* Write Brightness Display register */
#define LCD_RDDISBV 0x52 /* Read Display Brightness */
#define LCD_WCD 0x53 /* Write Control Display register*/
#define LCD_RDCTRLD 0x54 /* Read CTRL Display */
#define LCD_WRCABC 0x55 /* Write Content Adaptive Brightness Control */
#define LCD_RDCABC 0x56 /* Read Content Adaptive Brightness Control */
#define LCD_WRITE_CABC 0x5E /* Write CABC Minimum Brightness */
#define LCD_READ_CABC 0x5F /* Read CABC Minimum Brightness */
#define LCD_READ_ID1 0xDA /* Read ID1 */
#define LCD_READ_ID2 0xDB /* Read ID2 */
#define LCD_READ_ID3 0xDC /* Read ID3 */
/* Level 2 Commands */
#define LCD_RGB_INTERFACE 0xB0 /* RGB Interface Signal Control */
#define LCD_FRMCTR1 0xB1 /* Frame Rate Control (In Normal Mode) */
#define LCD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle Mode) */
#define LCD_FRMCTR3 0xB3 /* Frame Rate Control (In Partial Mode) */
#define LCD_INVTR 0xB4 /* Display Inversion Control */
#define LCD_BPC 0xB5 /* Blanking Porch Control register */
#define LCD_DFC 0xB6 /* Display Function Control register */
#define LCD_ETMOD 0xB7 /* Entry Mode Set */
#define LCD_BACKLIGHT1 0xB8 /* Backlight Control 1 */
#define LCD_BACKLIGHT2 0xB9 /* Backlight Control 2 */
#define LCD_BACKLIGHT3 0xBA /* Backlight Control 3 */
#define LCD_BACKLIGHT4 0xBB /* Backlight Control 4 */
#define LCD_BACKLIGHT5 0xBC /* Backlight Control 5 */
#define LCD_BACKLIGHT7 0xBE /* Backlight Control 7 */
#define LCD_BACKLIGHT8 0xBF /* Backlight Control 8 */
#define LCD_POWER1 0xC0 /* Power Control 1 register */
#define LCD_POWER2 0xC1 /* Power Control 2 register */
#define LCD_VCOM1 0xC5 /* VCOM Control 1 register */
#define LCD_VCOM2 0xC7 /* VCOM Control 2 register */
#define LCD_NVMWR 0xD0 /* NV Memory Write */
#define LCD_NVMPKEY 0xD1 /* NV Memory Protection Key */
#define LCD_RDNVM 0xD2 /* NV Memory Status Read */
#define LCD_READ_ID4 0xD3 /* Read ID4 */
#define LCD_PGAMMA 0xE0 /* Positive Gamma Correction register */
#define LCD_NGAMMA 0xE1 /* Negative Gamma Correction register */
#define LCD_DGAMCTRL1 0xE2 /* Digital Gamma Control 1 */
#define LCD_DGAMCTRL2 0xE3 /* Digital Gamma Control 2 */
#define LCD_INTERFACE 0xF6 /* Interface control register */
/* Extend register commands */
#define LCD_POWERA 0xCB /* Power control A register */
#define LCD_POWERB 0xCF /* Power control B register */
#define LCD_DTCA 0xE8 /* Driver timing control A */
#define LCD_DTCB 0xEA /* Driver timing control B */
#define LCD_POWER_SEQ 0xED /* Power on sequence register */
#define LCD_3GAMMA_EN 0xF2 /* 3 Gamma enable register */
#define LCD_PRC 0xF7 /* Pump ratio control register */
/* Size of read registers */
#define LCD_READ_ID4_SIZE 3 /* Size of Read ID4 */
/*############################### SPIx #######################################*/
#define DISCOVERY_SPIx SPI5
#define DISCOVERY_SPIx_CLK_ENABLE() __HAL_RCC_SPI5_CLK_ENABLE()
#define DISCOVERY_SPIx_GPIO_PORT GPIOF /* GPIOF */
#define DISCOVERY_SPIx_AF GPIO_AF5_SPI5
#define DISCOVERY_SPIx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE()
#define DISCOVERY_SPIx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE()
#define DISCOVERY_SPIx_SCK_PIN GPIO_PIN_7 /* PF.07 */
#define DISCOVERY_SPIx_MISO_PIN GPIO_PIN_8 /* PF.08 */
#define DISCOVERY_SPIx_MOSI_PIN GPIO_PIN_9 /* PF.09 */
/* Maximum Timeout values for flags waiting loops. These timeouts are not based
on accurate values, they just guarantee that the application will not remain
stuck if the SPI communication is corrupted.
You may modify these timeout values depending on CPU frequency and
application conditions (interrupts routines ...). */
#define SPIx_TIMEOUT_MAX ((uint32_t)0x1000)
/*################################ LCD #######################################*/
/* Chip Select macro definition */
#define LCD_CS_LOW() \
HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_RESET)
#define LCD_CS_HIGH() \
HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_SET)
/* Set WRX High to send data */
#define LCD_WRX_LOW() \
HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_RESET)
#define LCD_WRX_HIGH() \
HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_SET)
/* Set WRX High to send data */
#define LCD_RDX_LOW() \
HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_RESET)
#define LCD_RDX_HIGH() \
HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_SET)
/**
* @brief LCD Control pin
*/
#define LCD_NCS_PIN GPIO_PIN_2
#define LCD_NCS_GPIO_PORT GPIOC
#define LCD_NCS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define LCD_NCS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
/**
* @}
*/
/**
* @brief LCD Command/data pin
*/
#define LCD_WRX_PIN GPIO_PIN_13
#define LCD_WRX_GPIO_PORT GPIOD
#define LCD_WRX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define LCD_WRX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
#define LCD_RDX_PIN GPIO_PIN_12
#define LCD_RDX_GPIO_PORT GPIOD
#define LCD_RDX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define LCD_RDX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
static SPI_HandleTypeDef SpiHandle;
uint32_t SpixTimeout =
SPIx_TIMEOUT_MAX; /*<! Value of Timeout when SPI communication fails */
/* SPIx bus function */
static void SPIx_Init(void);
static void ili9341_Write(uint16_t Value);
static uint32_t ili9341_Read(uint8_t ReadSize);
static void ili9341_Error(void);
/**
* @brief SPIx Bus initialization
*/
static void SPIx_Init(void) {
if (HAL_SPI_GetState(&SpiHandle) == HAL_SPI_STATE_RESET) {
/* SPI configuration -----------------------------------------------------*/
SpiHandle.Instance = DISCOVERY_SPIx;
/* SPI baudrate is set to 5.6 MHz (PCLK2/SPI_BaudRatePrescaler = 90/16
= 5.625 MHz) to verify these constraints:
- ILI9341 LCD SPI interface max baudrate is 10MHz for write and 6.66MHz
for read
- l3gd20 SPI interface max baudrate is 10MHz for write/read
- PCLK2 frequency is set to 90 MHz
*/
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
/* On STM32F429I-Discovery, LCD ID cannot be read then keep a common
* configuration */
/* for LCD and GYRO (SPI_DIRECTION_2LINES) */
/* Note: To read a register a LCD, SPI_DIRECTION_1LINE should be set */
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLED;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
HAL_SPI_Init(&SpiHandle);
}
}
/**
* @brief SPIx error treatment function.
*/
static void ili9341_Error(void) {
/* De-initialize the SPI communication BUS */
HAL_SPI_DeInit(&SpiHandle);
/* Re- Initialize the SPI communication BUS */
SPIx_Init();
}
/**
* @brief Reads 4 bytes from device.
* @param ReadSize: Number of bytes to read (max 4 bytes)
* @retval Value read on the SPI
*/
static uint32_t ili9341_Read(uint8_t ReadSize) {
HAL_StatusTypeDef status = HAL_OK;
uint32_t readvalue;
status =
HAL_SPI_Receive(&SpiHandle, (uint8_t*)&readvalue, ReadSize, SpixTimeout);
/* Check the communication status */
if (status != HAL_OK) {
/* Re-Initialize the BUS */
ili9341_Error();
}
return readvalue;
}
/**
* @brief Writes a byte to device.
* @param Value: value to be written
*/
static void ili9341_Write(uint16_t Value) {
HAL_StatusTypeDef status = HAL_OK;
status = HAL_SPI_Transmit(&SpiHandle, (uint8_t*)&Value, 1, SpixTimeout);
/* Check the communication status */
if (status != HAL_OK) {
/* Re-Initialize the BUS */
ili9341_Error();
}
}
void ili9341_spi_init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure NCS in Output Push-Pull mode */
LCD_WRX_GPIO_CLK_ENABLE();
GPIO_InitStructure.Pin = LCD_WRX_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(LCD_WRX_GPIO_PORT, &GPIO_InitStructure);
LCD_RDX_GPIO_CLK_ENABLE();
GPIO_InitStructure.Pin = LCD_RDX_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(LCD_RDX_GPIO_PORT, &GPIO_InitStructure);
/* Configure the LCD Control pins ----------------------------------------*/
LCD_NCS_GPIO_CLK_ENABLE();
/* Configure NCS in Output Push-Pull mode */
GPIO_InitStructure.Pin = LCD_NCS_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
HAL_GPIO_Init(LCD_NCS_GPIO_PORT, &GPIO_InitStructure);
/* Set or Reset the control line */
LCD_CS_LOW();
LCD_CS_HIGH();
/* Enable SPIx clock */
DISCOVERY_SPIx_CLK_ENABLE();
/* Enable DISCOVERY_SPI GPIO clock */
DISCOVERY_SPIx_GPIO_CLK_ENABLE();
/* configure SPI SCK, MOSI and MISO */
GPIO_InitStructure.Pin = (DISCOVERY_SPIx_SCK_PIN | DISCOVERY_SPIx_MOSI_PIN |
DISCOVERY_SPIx_MISO_PIN);
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
GPIO_InitStructure.Speed = GPIO_SPEED_MEDIUM;
GPIO_InitStructure.Alternate = DISCOVERY_SPIx_AF;
HAL_GPIO_Init(DISCOVERY_SPIx_GPIO_PORT, &GPIO_InitStructure);
SPIx_Init();
}
/**
* @brief Writes register value.
*/
void ili9341_WriteData(uint16_t RegValue) {
/* Set WRX to send data */
LCD_WRX_HIGH();
/* Reset LCD control line(/CS) and Send data */
LCD_CS_LOW();
ili9341_Write(RegValue);
/* Deselect: Chip Select high */
LCD_CS_HIGH();
}
/**
* @brief Writes register address.
*/
void ili9341_WriteReg(uint8_t Reg) {
/* Reset WRX to send command */
LCD_WRX_LOW();
/* Reset LCD control line(/CS) and Send command */
LCD_CS_LOW();
ili9341_Write(Reg);
/* Deselect: Chip Select high */
LCD_CS_HIGH();
}
/**
* @brief Reads register value.
* @param RegValue Address of the register to read
* @param ReadSize Number of bytes to read
* @retval Content of the register value
*/
uint32_t ili9341_ReadData(uint16_t RegValue, uint8_t ReadSize) {
uint32_t readvalue = 0;
/* Select: Chip Select low */
LCD_CS_LOW();
/* Reset WRX to send command */
LCD_WRX_LOW();
ili9341_Write(RegValue);
readvalue = ili9341_Read(ReadSize);
/* Set WRX to send data */
LCD_WRX_HIGH();
/* Deselect: Chip Select high */
LCD_CS_HIGH();
return readvalue;
}
void ili9341_init(void) {
/* Initialize ILI9341 low level bus layer ----------------------------------*/
ili9341_spi_init();
ili9341_WriteReg(LCD_DISPLAY_OFF);
/* Configure LCD */
ili9341_WriteReg(0xCA);
ili9341_WriteData(0xC3);
ili9341_WriteData(0x08);
ili9341_WriteData(0x50);
ili9341_WriteReg(LCD_POWERB);
ili9341_WriteData(0x00);
ili9341_WriteData(0xC1);
ili9341_WriteData(0x30);
ili9341_WriteReg(LCD_POWER_SEQ);
ili9341_WriteData(0x64);
ili9341_WriteData(0x03);
ili9341_WriteData(0x12);
ili9341_WriteData(0x81);
ili9341_WriteReg(LCD_DTCA);
ili9341_WriteData(0x85);
ili9341_WriteData(0x00);
ili9341_WriteData(0x78);
ili9341_WriteReg(LCD_POWERA);
ili9341_WriteData(0x39);
ili9341_WriteData(0x2C);
ili9341_WriteData(0x00);
ili9341_WriteData(0x34);
ili9341_WriteData(0x02);
ili9341_WriteReg(LCD_PRC);
ili9341_WriteData(0x20);
ili9341_WriteReg(LCD_DTCB);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteReg(LCD_FRMCTR1);
ili9341_WriteData(0x00);
ili9341_WriteData(0x1B);
ili9341_WriteReg(LCD_DFC);
ili9341_WriteData(0x0A);
ili9341_WriteData(0xA2);
ili9341_WriteReg(LCD_POWER1);
ili9341_WriteData(0x10);
ili9341_WriteReg(LCD_POWER2);
ili9341_WriteData(0x10);
ili9341_WriteReg(LCD_VCOM1);
ili9341_WriteData(0x45);
ili9341_WriteData(0x15);
ili9341_WriteReg(LCD_VCOM2);
ili9341_WriteData(0x90);
ili9341_WriteReg(LCD_MAC);
ili9341_WriteData(0xC8);
ili9341_WriteReg(LCD_3GAMMA_EN);
ili9341_WriteData(0x00);
ili9341_WriteReg(LCD_RGB_INTERFACE);
ili9341_WriteData(0xC2);
ili9341_WriteReg(LCD_DFC);
ili9341_WriteData(0x0A);
ili9341_WriteData(0xA7);
ili9341_WriteData(0x27);
ili9341_WriteData(0x04);
/* Colomn address set */
ili9341_WriteReg(LCD_COLUMN_ADDR);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteData(0xEF);
/* Page address set */
ili9341_WriteReg(LCD_PAGE_ADDR);
ili9341_WriteData(0x00);
ili9341_WriteData(0x00);
ili9341_WriteData(0x01);
ili9341_WriteData(0x3F);
ili9341_WriteReg(LCD_INTERFACE);
ili9341_WriteData(0x01);
ili9341_WriteData(0x00);
ili9341_WriteData(0x06);
ili9341_WriteReg(LCD_GRAM);
HAL_Delay(200);
ili9341_WriteReg(LCD_GAMMA);
ili9341_WriteData(0x01);
ili9341_WriteReg(LCD_PGAMMA);
ili9341_WriteData(0x0F);
ili9341_WriteData(0x29);
ili9341_WriteData(0x24);
ili9341_WriteData(0x0C);
ili9341_WriteData(0x0E);
ili9341_WriteData(0x09);
ili9341_WriteData(0x4E);
ili9341_WriteData(0x78);
ili9341_WriteData(0x3C);
ili9341_WriteData(0x09);
ili9341_WriteData(0x13);
ili9341_WriteData(0x05);
ili9341_WriteData(0x17);
ili9341_WriteData(0x11);
ili9341_WriteData(0x00);
ili9341_WriteReg(LCD_NGAMMA);
ili9341_WriteData(0x00);
ili9341_WriteData(0x16);
ili9341_WriteData(0x1B);
ili9341_WriteData(0x04);
ili9341_WriteData(0x11);
ili9341_WriteData(0x07);
ili9341_WriteData(0x31);
ili9341_WriteData(0x33);
ili9341_WriteData(0x42);
ili9341_WriteData(0x05);
ili9341_WriteData(0x0C);
ili9341_WriteData(0x0A);
ili9341_WriteData(0x28);
ili9341_WriteData(0x2F);
ili9341_WriteData(0x0F);
ili9341_WriteReg(LCD_SLEEP_OUT);
HAL_Delay(200);
ili9341_WriteReg(LCD_DISPLAY_ON);
/* GRAM start writing */
ili9341_WriteReg(LCD_GRAM);
}

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

@ -0,0 +1,393 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "xdisplay.h"
#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 128)
#error "Incompatible display resolution"
#endif
// This file implements display driver for monochromatic display V-2864KSWEG01
// with 128x128 resolution connected to CPU via SPI interface.
//
// This type of displayed was used on some preliminary dev kits for T3T1 (Trezor
// TS3)
// Display driver context.
typedef struct {
// Frame buffer (8-bit Mono)
uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY];
// Current display orientation (0 or 180)
int orientation_angle;
// Current backlight level ranging from 0 to 255
int backlight_level;
} display_driver_t;
// Display driver instance
static display_driver_t g_display_driver;
// Macros to access display parallel interface
// FSMC/FMC Bank 1 - NOR/PSRAM 1
#define DISPLAY_MEMORY_BASE 0x60000000
#define DISPLAY_MEMORY_PIN 16
#define CMD_ADDR *((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE)))
#define DATA_ADDR \
(*((__IO uint8_t *)((uint32_t)(DISPLAY_MEMORY_BASE | \
(1 << DISPLAY_MEMORY_PIN)))))
#define ISSUE_CMD_BYTE(X) \
do { \
(CMD_ADDR) = (X); \
} while (0)
#define ISSUE_DATA_BYTE(X) \
do { \
(DATA_ADDR) = (X); \
} while (0)
// ---------------------------------------------------------------------------
// Display controller registers
// ---------------------------------------------------------------------------
#define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4
#define OLED_DISPLAYALLON 0xA5
#define OLED_NORMALDISPLAY 0xA6
#define OLED_INVERTDISPLAY 0xA7
#define OLED_DISPLAYOFF 0xAE
#define OLED_DISPLAYON 0xAF
#define OLED_SETDISPLAYOFFSET 0xD3
#define OLED_SETCOMPINS 0xDA
#define OLED_SETVCOMDETECT 0xDB
#define OLED_SETDISPLAYCLOCKDIV 0xD5
#define OLED_SETPRECHARGE 0xD9
#define OLED_SETMULTIPLEX 0xA8
#define OLED_SETLOWCOLUMN 0x00
#define OLED_SETHIGHCOLUMN 0x10
#define OLED_SETSTARTLINE 0x40
#define OLED_MEMORYMODE 0x20
#define OLED_COMSCANINC 0xC0
#define OLED_COMSCANDEC 0xC8
#define OLED_SEGREMAP 0xA0
#define OLED_CHARGEPUMP 0x8D
// Dipslay specific initialization sequence
static const uint8_t ug_2828tswig01_init_seq[] = {
OLED_DISPLAYOFF,
// Divide ratio 0, Oscillator Frequency +0%
OLED_SETDISPLAYCLOCKDIV, 0x50,
// Set Memory Addressing Mode - page addressing mode
0x20,
// Set Contrast Control Register
OLED_SETCONTRAST, 0x8F,
// Set DC-DC Setting: (Double Bytes Command)
0xAD, 0x8A,
// Set Segment Re-map
OLED_SEGREMAP | 0x01,
// Set COM Output Scan Direction
OLED_COMSCANDEC,
// Set Display Start Line:Double Bytes Command
0xDC, 0x00,
// Set Display Offset:Double Bytes Command
OLED_SETDISPLAYOFFSET, 0x00,
// Set Discharge / Pre-Charge Period (Double Bytes Command)
OLED_SETPRECHARGE, 0x22,
// Set VCOM Deselect Level
OLED_SETVCOMDETECT, 0x35,
// Set Multiplex Ratio
OLED_SETMULTIPLEX, 0x7F,
// Set Page
0xB0,
// Reset column
OLED_SETLOWCOLUMN | 0, OLED_SETHIGHCOLUMN | 0,
// Set Entire Display Off
// to be clear, this command turns off the function
// which turns entire display on, but it does not clear
// the data in display RAM
OLED_DISPLAYALLON_RESUME,
// Set Normal Display
OLED_NORMALDISPLAY};
static void __attribute__((unused)) display_sleep(void) {
// Display OFF
ISSUE_CMD_BYTE(OLED_DISPLAYOFF);
HAL_Delay(5);
// Vpp disable
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_RESET);
}
static void display_resume(void) {
// Vpp enable
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_8, GPIO_PIN_SET);
// 100 ms mandatory wait
HAL_Delay(100);
// Display ON
ISSUE_CMD_BYTE(OLED_DISPLAYON);
}
// Sets the display cursor to the specific row and column
static void display_set_page_and_col(uint8_t page, uint8_t col) {
if (page < (DISPLAY_RESY / 8)) {
ISSUE_CMD_BYTE(0xB0 | (page & 0xF));
if (col < DISPLAY_RESX) {
ISSUE_CMD_BYTE(OLED_SETHIGHCOLUMN | ((col & 0x70) >> 4));
ISSUE_CMD_BYTE(OLED_SETLOWCOLUMN | (col & 0x0F));
} else {
// Reset column to start
ISSUE_CMD_BYTE(OLED_SETHIGHCOLUMN);
ISSUE_CMD_BYTE(OLED_SETLOWCOLUMN);
}
}
}
#define COLLECT_ROW_BYTE(src) \
(0 | (*(src + (0 * DISPLAY_RESX)) ? 128 : 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);
*/

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "xdisplay.h"
#ifdef USE_CONSUMPTION_MASK
#include "consumption_mask.h"
#endif
#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 64)
#error "Incompatible display resolution"
#endif
// This file implements display driver for monochromatic display V-2864KSWEG01
// with 128x64 resolution connected to CPU via SPI interface.
//
// This type of display is used with T3T1 model (Trezor TS3)
// Display driver context.
typedef struct {
// SPI driver instance
SPI_HandleTypeDef spi;
// Frame buffer (8-bit Mono)
uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY];
// Current display orientation (0 or 180)
int orientation_angle;
// Current backlight level ranging from 0 to 255
int backlight_level;
} display_driver_t;
// Display driver instance
static display_driver_t g_display_driver;
// Display controller registers
#define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4
#define OLED_DISPLAYALLON 0xA5
#define OLED_NORMALDISPLAY 0xA6
#define OLED_INVERTDISPLAY 0xA7
#define OLED_DISPLAYOFF 0xAE
#define OLED_DISPLAYON 0xAF
#define OLED_SETDISPLAYOFFSET 0xD3
#define OLED_SETCOMPINS 0xDA
#define OLED_SETVCOMDETECT 0xDB
#define OLED_SETDISPLAYCLOCKDIV 0xD5
#define OLED_SETPRECHARGE 0xD9
#define OLED_SETMULTIPLEX 0xA8
#define OLED_SETLOWCOLUMN 0x00
#define OLED_SETHIGHCOLUMN 0x10
#define OLED_SETSTARTLINE 0x40
#define OLED_MEMORYMODE 0x20
#define OLED_COMSCANINC 0xC0
#define OLED_COMSCANDEC 0xC8
#define OLED_SEGREMAP 0xA0
#define OLED_CHARGEPUMP 0x8D
// Display controller initialization sequence
static const uint8_t vg_2864ksweg01_init_seq[] = {OLED_DISPLAYOFF,
OLED_SETDISPLAYCLOCKDIV,
0x80,
OLED_SETMULTIPLEX,
0x3F, // 128x64
OLED_SETDISPLAYOFFSET,
0x00,
OLED_SETSTARTLINE | 0x00,
OLED_CHARGEPUMP,
0x14,
OLED_MEMORYMODE,
0x00,
OLED_SEGREMAP | 0x01,
OLED_COMSCANDEC,
OLED_SETCOMPINS,
0x12, // 128x64
OLED_SETCONTRAST,
0xCF,
OLED_SETPRECHARGE,
0xF1,
OLED_SETVCOMDETECT,
0x40,
OLED_DISPLAYALLON_RESUME,
OLED_NORMALDISPLAY,
OLED_DISPLAYON};
// Configures SPI driver/controller
static bool display_init_spi(display_driver_t *drv) {
drv->spi.Instance = OLED_SPI;
drv->spi.State = HAL_SPI_STATE_RESET;
drv->spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
drv->spi.Init.Direction = SPI_DIRECTION_2LINES;
drv->spi.Init.CLKPhase = SPI_PHASE_1EDGE;
drv->spi.Init.CLKPolarity = SPI_POLARITY_LOW;
drv->spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
drv->spi.Init.CRCPolynomial = 7;
drv->spi.Init.DataSize = SPI_DATASIZE_8BIT;
drv->spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
drv->spi.Init.NSS = SPI_NSS_HARD_OUTPUT;
drv->spi.Init.TIMode = SPI_TIMODE_DISABLE;
drv->spi.Init.Mode = SPI_MODE_MASTER;
return (HAL_OK == HAL_SPI_Init(&drv->spi)) ? true : false;
}
// Sends specified number of bytes to the display via SPI interface
static void display_send_bytes(display_driver_t *drv, const uint8_t *data,
size_t len) {
volatile int32_t timeout = 1000; // !@# 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) {
}
*/

@ -46,12 +46,12 @@ uint8_t *const DISPLAY_DATA_ADDRESS = 0;
uint16_t cursor_x = 0;
uint16_t cursor_y = 0;
uint16_t window_x0 = 0;
uint16_t window_y0 = MAX_DISPLAY_RESX - 1;
uint16_t window_y0 = DISPLAY_RESX - 1;
uint16_t window_x1 = 0;
uint16_t window_y1 = MAX_DISPLAY_RESY - 1;
uint16_t window_y1 = DISPLAY_RESY - 1;
void display_pixeldata(uint16_t c) {
((uint16_t *)LCD_FRAME_BUFFER)[(cursor_y * MAX_DISPLAY_RESX) + cursor_x] = c;
((uint16_t *)LCD_FRAME_BUFFER)[(cursor_y * DISPLAY_RESX) + cursor_x] = c;
cursor_x++;
@ -83,9 +83,9 @@ void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
/* Layer Init */
Layercfg.WindowX0 = 0;
Layercfg.WindowX1 = MAX_DISPLAY_RESX;
Layercfg.WindowX1 = DISPLAY_RESX;
Layercfg.WindowY0 = 0;
Layercfg.WindowY1 = MAX_DISPLAY_RESY;
Layercfg.WindowY1 = DISPLAY_RESY;
Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
Layercfg.FBStartAdress = FB_Address;
Layercfg.Alpha = 255;
@ -95,8 +95,8 @@ void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
Layercfg.Backcolor.Red = 0;
Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
Layercfg.ImageWidth = MAX_DISPLAY_RESX;
Layercfg.ImageHeight = MAX_DISPLAY_RESY;
Layercfg.ImageWidth = DISPLAY_RESX;
Layercfg.ImageHeight = DISPLAY_RESY;
HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex);
@ -380,7 +380,7 @@ void display_efficient_clear(void) {
uint8_t *display_get_wr_addr(void) {
uint32_t address = LCD_FRAME_BUFFER;
/* Get the rectangle start address */
address = (address + (2 * ((cursor_y)*MAX_DISPLAY_RESX + (cursor_x))));
address = (address + (2 * ((cursor_y)*DISPLAY_RESX + (cursor_x))));
return (uint8_t *)address;
}
@ -413,7 +413,7 @@ void display_shift_window(uint16_t pixels) {
}
uint16_t display_get_window_offset(void) {
return MAX_DISPLAY_RESX - display_get_window_width();
return DISPLAY_RESX - display_get_window_width();
}
void display_finish_actions(void) {}

@ -5,8 +5,8 @@
#include STM32_HAL_H
#define TREZOR_FONT_BPP 4
#define DISPLAY_FRAMEBUFFER_WIDTH MAX_DISPLAY_RESX
#define DISPLAY_FRAMEBUFFER_HEIGHT MAX_DISPLAY_RESY
#define DISPLAY_FRAMEBUFFER_WIDTH DISPLAY_RESX
#define DISPLAY_FRAMEBUFFER_HEIGHT DISPLAY_RESY
#define DISPLAY_FRAMEBUFFER_OFFSET_X 0
#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565

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

@ -20,9 +20,9 @@
#include STM32_HAL_H
#include <stddef.h>
#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;

@ -260,8 +260,8 @@ uint32_t touch_read(void) {
// first touch) (tested with FT6206)
const uint32_t event_flag = touch_data[3] & 0xC0;
if (touch_data[1] == GESTURE_NO_GESTURE) {
xy = TRANSFORM_TOUCH_COORDS((X_POS_MSB << 8) | X_POS_LSB,
(Y_POS_MSB << 8) | Y_POS_LSB);
xy = touch_pack_xy((X_POS_MSB << 8) | X_POS_LSB,
(Y_POS_MSB << 8) | Y_POS_LSB);
if ((number_of_touch_points == 1) && (event_flag == EVENT_PRESS_DOWN)) {
touching = 1;
return TOUCH_START | xy;

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

@ -0,0 +1,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 <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#include TREZOR_BOARD
#include STM32_HAL_H
#include "display_internal.h"
#include "xdisplay.h"
#if (DISPLAY_RESX != 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);
*/

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

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
#define TREZOR_HAL_DISPLAY_INTERNAL_H
#include <stdint.h>
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual 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

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

@ -3,10 +3,6 @@
#include STM32_HAL_H
#define MAX_DISPLAY_RESX 240
#define MAX_DISPLAY_RESY 240
#define DISPLAY_RESX 240
#define DISPLAY_RESY 240
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888
#define DISPLAY_FRAMEBUFFER_WIDTH 768
#define DISPLAY_FRAMEBUFFER_HEIGHT 480

@ -0,0 +1,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 <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
#include <xdisplay.h>
#include <SDL.h>
#include <SDL_image.h>
#include "common.h"
#include "profile.h"
#define EMULATOR_BORDER 16
#if defined TREZOR_MODEL_T
#ifdef TREZOR_EMULATOR_RASPI
#define WINDOW_WIDTH 480
#define WINDOW_HEIGHT 320
#define TOUCH_OFFSET_X 110
#define TOUCH_OFFSET_Y 40
#else
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 600
#define TOUCH_OFFSET_X 80
#define TOUCH_OFFSET_Y 110
#endif
#elif defined TREZOR_MODEL_1
#define WINDOW_WIDTH 200
#define WINDOW_HEIGHT 340
#define TOUCH_OFFSET_X 36
#define TOUCH_OFFSET_Y 92
#elif defined TREZOR_MODEL_R
#define WINDOW_WIDTH 193
#define WINDOW_HEIGHT 339
#define TOUCH_OFFSET_X 32
#define TOUCH_OFFSET_Y 84
#elif defined TREZOR_MODEL_T3T1
#define WINDOW_WIDTH 400
#define WINDOW_HEIGHT 600
#define TOUCH_OFFSET_X 80
#define TOUCH_OFFSET_Y 110
#else
#error Unknown Trezor model
#endif
typedef struct {
// Current display orientation (0 or 180)
int orientation_angle;
// Current backlight level ranging from 0 to 255
int backlight_level;
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Surface *buffer;
SDL_Texture *texture;
SDL_Texture *background;
SDL_Surface *prev_saved;
#if DISPLAY_MONO
// SDL2 does not support 8bit surface/texture
// and we have to simulate it
uint8_t mono_framebuf[DISPLAY_RESX * DISPLAY_RESY];
#endif
} display_driver_t;
static display_driver_t g_display_driver;
//!@# TODO get rid of this...
int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY;
int sdl_touch_offset_x, sdl_touch_offset_y;
void display_deinit(void) {
display_driver_t *drv = &g_display_driver;
SDL_FreeSurface(drv->prev_saved);
SDL_FreeSurface(drv->buffer);
if (drv->background != NULL) {
SDL_DestroyTexture(drv->background);
}
if (drv->texture != NULL) {
SDL_DestroyTexture(drv->texture);
}
if (drv->renderer != NULL) {
SDL_DestroyRenderer(drv->renderer);
}
if (drv->window != NULL) {
SDL_DestroyWindow(drv->window);
}
SDL_Quit();
}
void display_init(void) {
display_driver_t *drv = &g_display_driver;
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_Init error");
}
atexit(display_deinit);
char *window_title = NULL;
char *window_title_alloc = NULL;
if (asprintf(&window_title_alloc, "Trezor^emu: %s", profile_name()) > 0) {
window_title = window_title_alloc;
} else {
window_title = "Trezor^emu";
window_title_alloc = NULL;
}
drv->window =
SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT,
#ifdef TREZOR_EMULATOR_RASPI
SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
#else
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
#endif
);
free(window_title_alloc);
if (!drv->window) {
printf("%s\n", SDL_GetError());
ensure(secfalse, "SDL_CreateWindow error");
}
drv->renderer = SDL_CreateRenderer(drv->window, -1, SDL_RENDERER_SOFTWARE);
if (!drv->renderer) {
printf("%s\n", SDL_GetError());
SDL_DestroyWindow(drv->window);
ensure(secfalse, "SDL_CreateRenderer error");
}
SDL_SetRenderDrawColor(drv->renderer, 0, 0, 0, 255);
SDL_RenderClear(drv->renderer);
drv->buffer = SDL_CreateRGBSurface(0, DISPLAY_RESX, DISPLAY_RESY, 16, 0xF800,
0x07E0, 0x001F, 0x0000);
drv->texture = SDL_CreateTexture(drv->renderer, SDL_PIXELFORMAT_RGB565,
SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX,
DISPLAY_RESY);
SDL_SetTextureBlendMode(drv->texture, SDL_BLENDMODE_BLEND);
#ifdef __APPLE__
// macOS Mojave SDL black screen workaround
SDL_PumpEvents();
SDL_SetWindowSize(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;
}

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

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

@ -0,0 +1,34 @@
#ifndef TREZORHAL_DISPLAY_LEGACY_H
#define TREZORHAL_DISPLAY_LEGACY_H
#include <buffers.h>
#include <stdint.h>
#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

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

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

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

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

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

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

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

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

Loading…
Cancel
Save