From afefc174786529fecbe12ed25250f3609e1d2aaf Mon Sep 17 00:00:00 2001 From: tychovrahe Date: Wed, 20 Dec 2023 22:33:52 +0100 Subject: [PATCH] refactor(core): use internal framebuffer on T3T1 (with ST7789V display controller) [no changelog] --- core/SConscript.bootloader | 2 +- core/embed/boardloader/memory_stm32u58.ld | 1 + core/embed/bootloader/memory_stm32u58.ld | 1 + core/embed/firmware/memory_T3T1.ld | 1 + core/embed/lib/display_interface.h | 1 + core/embed/prodtest/memory_stm32u58.ld | 1 + core/embed/reflash/memory_stm32u58.ld | 1 + core/embed/rust/src/trezorhal/display.rs | 13 +- core/embed/trezorhal/boards/trezor_t3t1_v4.h | 4 + core/embed/trezorhal/stm32f4/backlight_pwm.c | 2 + core/embed/trezorhal/stm32f4/common.c | 1 + core/embed/trezorhal/stm32f4/displays/ltdc.c | 2 + .../trezorhal/stm32f4/displays/st7789v.c | 375 +++++++++++++++++- .../trezorhal/stm32f4/displays/st7789v.h | 25 +- .../stm32f4/displays/ug-2828tswig01.c | 2 + .../stm32f4/displays/vg-2864ksweg01.c | 2 + core/embed/trezorhal/stm32u5/common.c | 2 +- core/embed/trezorhal/stm32u5/displays/dsi.c | 2 + core/embed/trezorhal/unix/display-unix.c | 2 + core/site_scons/boards/stm32f4_common.py | 2 +- core/site_scons/boards/stm32u5_common.py | 3 +- core/site_scons/boards/trezor_t3t1_v4.py | 6 + 22 files changed, 420 insertions(+), 31 deletions(-) diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 25a6d6c14d..2c2e9a7cb2 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -20,7 +20,7 @@ if TREZOR_MODEL in ('1', ): ) Return() -FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga"] +FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "dma2d"] CCFLAGS_MOD = '' CPPPATH_MOD = [] diff --git a/core/embed/boardloader/memory_stm32u58.ld b/core/embed/boardloader/memory_stm32u58.ld index 8fe61fed3b..986813e562 100644 --- a/core/embed/boardloader/memory_stm32u58.ld +++ b/core/embed/boardloader/memory_stm32u58.ld @@ -92,6 +92,7 @@ SECTIONS { __fb_start = .; *(.fb1*); *(.fb2*); + *(.framebuffer_select*); __fb_end = .; . = ALIGN(4); } >SRAM3 diff --git a/core/embed/bootloader/memory_stm32u58.ld b/core/embed/bootloader/memory_stm32u58.ld index e5bc29b301..4111e8fed6 100644 --- a/core/embed/bootloader/memory_stm32u58.ld +++ b/core/embed/bootloader/memory_stm32u58.ld @@ -93,6 +93,7 @@ SECTIONS { __fb_start = .; *(.fb1*); *(.fb2*); + *(.framebuffer_select*); __fb_end = .; . = ALIGN(4); } >SRAM3 diff --git a/core/embed/firmware/memory_T3T1.ld b/core/embed/firmware/memory_T3T1.ld index 1f8abef7dd..f074a5e230 100644 --- a/core/embed/firmware/memory_T3T1.ld +++ b/core/embed/firmware/memory_T3T1.ld @@ -104,6 +104,7 @@ SECTIONS { __fb_start = .; *(.fb1*); *(.fb2*); + *(.framebuffer_select*); __fb_end = .; . = ALIGN(4); } >SRAM3 diff --git a/core/embed/lib/display_interface.h b/core/embed/lib/display_interface.h index 2b48c72358..19f68161ac 100644 --- a/core/embed/lib/display_interface.h +++ b/core/embed/lib/display_interface.h @@ -58,6 +58,7 @@ void display_init(void); void display_reinit(void); void display_sync(void); void display_refresh(void); +void display_finish_actions(void); const char *display_save(const char *prefix); void display_clear_save(void); diff --git a/core/embed/prodtest/memory_stm32u58.ld b/core/embed/prodtest/memory_stm32u58.ld index 54795edb71..4dfb376aa5 100644 --- a/core/embed/prodtest/memory_stm32u58.ld +++ b/core/embed/prodtest/memory_stm32u58.ld @@ -108,6 +108,7 @@ SECTIONS { __fb_start = .; *(.fb1*); *(.fb2*); + *(.framebuffer_select*); __fb_end = .; . = ALIGN(4); } >SRAM3 diff --git a/core/embed/reflash/memory_stm32u58.ld b/core/embed/reflash/memory_stm32u58.ld index a632e270c2..c298dbac1b 100644 --- a/core/embed/reflash/memory_stm32u58.ld +++ b/core/embed/reflash/memory_stm32u58.ld @@ -109,6 +109,7 @@ SECTIONS { __fb_start = .; *(.fb1*); *(.fb2*); + *(.framebuffer_select*); __fb_end = .; . = ALIGN(4); } >SRAM3 diff --git a/core/embed/rust/src/trezorhal/display.rs b/core/embed/rust/src/trezorhal/display.rs index 8fb2e70abf..95a17350be 100644 --- a/core/embed/rust/src/trezorhal/display.rs +++ b/core/embed/rust/src/trezorhal/display.rs @@ -80,7 +80,11 @@ pub fn text_baseline(font: i32) -> i16 { } #[inline(always)] -#[cfg(all(feature = "disp_i8080_16bit_dw", not(feature = "disp_i8080_8bit_dw")))] +#[cfg(all( + not(feature = "framebuffer"), + feature = "disp_i8080_16bit_dw", + not(feature = "disp_i8080_8bit_dw") +))] pub fn pixeldata(c: u16) { unsafe { ffi::DISPLAY_DATA_ADDRESS.write_volatile(c); @@ -93,7 +97,7 @@ pub fn get_fb_addr() -> FrameBuffer { } #[inline(always)] -#[cfg(feature = "disp_i8080_8bit_dw")] +#[cfg(all(not(feature = "framebuffer"), feature = "disp_i8080_8bit_dw"))] pub fn pixeldata(c: u16) { unsafe { ffi::DISPLAY_DATA_ADDRESS.write_volatile((c & 0xff) as u8); @@ -126,7 +130,10 @@ pub fn pixel(fb: FrameBuffer, x: i16, y: i16, c: u32) { } #[inline(always)] -#[cfg(not(any(feature = "disp_i8080_16bit_dw", feature = "disp_i8080_8bit_dw")))] +#[cfg(any( + feature = "framebuffer", + not(any(feature = "disp_i8080_16bit_dw", feature = "disp_i8080_8bit_dw")) +))] pub fn pixeldata(c: u16) { unsafe { ffi::display_pixeldata(c); diff --git a/core/embed/trezorhal/boards/trezor_t3t1_v4.h b/core/embed/trezorhal/boards/trezor_t3t1_v4.h index cf4ea3fa40..fa5807b009 100644 --- a/core/embed/trezorhal/boards/trezor_t3t1_v4.h +++ b/core/embed/trezorhal/boards/trezor_t3t1_v4.h @@ -22,6 +22,10 @@ #define DISPLAY_IDENTIFY 1 #define DISPLAY_TE_PORT GPIOD #define DISPLAY_TE_PIN GPIO_PIN_12 +#define DISPLAY_TE_INTERRUPT_HANDLER EXTI12_IRQHandler +#define DISPLAY_TE_INTERRUPT_NUM EXTI12_IRQn +#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 diff --git a/core/embed/trezorhal/stm32f4/backlight_pwm.c b/core/embed/trezorhal/stm32f4/backlight_pwm.c index becf4602fa..4c1cfa42e5 100644 --- a/core/embed/trezorhal/stm32f4/backlight_pwm.c +++ b/core/embed/trezorhal/stm32f4/backlight_pwm.c @@ -22,6 +22,8 @@ int backlight_pwm_set(int val) { return BACKLIGHT; } +int backlight_pwm_get(void) { return BACKLIGHT; } + void backlight_pwm_init(void) { // init peripherals BACKLIGHT_PWM_PORT_CLK_EN(); diff --git a/core/embed/trezorhal/stm32f4/common.c b/core/embed/trezorhal/stm32f4/common.c index 5e8eb5472f..23f9b82029 100644 --- a/core/embed/trezorhal/stm32f4/common.c +++ b/core/embed/trezorhal/stm32f4/common.c @@ -222,6 +222,7 @@ void collect_hw_entropy(void) { // which might be incompatible with the other layers older versions, // where this setting might be unknown void ensure_compatible_settings(void) { + display_finish_actions(); #ifdef TREZOR_MODEL_T display_set_big_endian(); display_orientation(0); diff --git a/core/embed/trezorhal/stm32f4/displays/ltdc.c b/core/embed/trezorhal/stm32f4/displays/ltdc.c index 505410ccb7..52cfd015da 100644 --- a/core/embed/trezorhal/stm32f4/displays/ltdc.c +++ b/core/embed/trezorhal/stm32f4/displays/ltdc.c @@ -415,3 +415,5 @@ void display_shift_window(uint16_t pixels) { uint16_t display_get_window_offset(void) { return MAX_DISPLAY_RESX - display_get_window_width(); } + +void display_finish_actions(void) {} diff --git a/core/embed/trezorhal/stm32f4/displays/st7789v.c b/core/embed/trezorhal/stm32f4/displays/st7789v.c index 53c0d2ac9f..60178b3d2c 100644 --- a/core/embed/trezorhal/stm32f4/displays/st7789v.c +++ b/core/embed/trezorhal/stm32f4/displays/st7789v.c @@ -19,11 +19,14 @@ #include #include +#include #include TREZOR_BOARD #include "backlight_pwm.h" #include "display_interface.h" +#include "irq.h" #include "memzero.h" #include "st7789v.h" +#include "supervise.h" #include STM32_HAL_H #ifdef TREZOR_MODEL_T @@ -57,6 +60,40 @@ __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS = (__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE | (DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN)); +#ifdef FRAMEBUFFER +#ifndef STM32U5 +#error Framebuffer only supported on STM32U5 for now +#endif + +#define DATA_TRANSFER(X) \ + DATA((X)&0xFF); \ + DATA((X) >> 8) + +__attribute__((section(".fb1"))) +ALIGN_32BYTES(static uint16_t PhysFrameBuffer0[DISPLAY_RESX * DISPLAY_RESY]); +__attribute__((section(".fb2"))) +ALIGN_32BYTES(static uint16_t PhysFrameBuffer1[DISPLAY_RESX * DISPLAY_RESY]); + +__attribute__(( + section(".framebuffer_select"))) static uint32_t act_frame_buffer = 0; + +static uint16_t window_x0 = 0; +static uint16_t window_y0 = 0; +static uint16_t window_x1 = 0; +static uint16_t window_y1 = 0; +static uint16_t cursor_x = 0; +static uint16_t cursor_y = 0; + +static volatile uint32_t dma_transfer_remaining = 0; +static volatile uint32_t dma_data_transferred = 0; +static DMA_HandleTypeDef DMA_Handle = {0}; + +void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma); + +#else +#define DATA_TRANSFER(X) PIXELDATA(X) +#endif + // section "9.1.3 RDDID (04h): Read Display ID" // of ST7789V datasheet #define DISPLAY_ID_ST7789V 0x858552U @@ -72,8 +109,6 @@ __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS = static int DISPLAY_ORIENTATION = -1; static display_padding_t DISPLAY_PADDING = {0}; -void display_pixeldata(uint16_t c) { PIXELDATA(c); } - void display_pixeldata_dirty(void) {} #ifdef DISPLAY_IDENTIFY @@ -160,7 +195,7 @@ static void display_unsleep(void) { } } -void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { +void panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { x0 += DISPLAY_PADDING.x; x1 += DISPLAY_PADDING.x; y0 += DISPLAY_PADDING.y; @@ -187,10 +222,14 @@ int display_orientation(int degrees) { if (degrees == 0 || degrees == 90 || degrees == 180 || degrees == 270) { DISPLAY_ORIENTATION = degrees; - display_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1); + panel_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1); +#ifdef FRAMEBUFFER + memzero(PhysFrameBuffer1, sizeof(PhysFrameBuffer1)); + memzero(PhysFrameBuffer0, sizeof(PhysFrameBuffer0)); +#endif for (uint32_t i = 0; i < MAX_DISPLAY_RESX * MAX_DISPLAY_RESY; i++) { // 2 bytes per pixel because we're using RGB 5-6-5 format - PIXELDATA(0x0000); + DATA_TRANSFER(0x0000); } #ifdef TREZOR_MODEL_T uint32_t id = display_identify(); @@ -202,6 +241,7 @@ int display_orientation(int degrees) { #else DISPLAY_PANEL_ROTATE(degrees, &DISPLAY_PADDING); #endif + panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); } } return DISPLAY_ORIENTATION; @@ -209,7 +249,19 @@ int display_orientation(int degrees) { int display_get_orientation(void) { return DISPLAY_ORIENTATION; } -int display_backlight(int val) { return backlight_pwm_set(val); } +int display_backlight(int val) { +#ifdef FRAMEBUFFER + // wait for DMA transfer to finish before changing backlight + // so that we know that panel has current data + if (backlight_pwm_get() != val && !is_mode_handler()) { + while (dma_transfer_remaining > 0) { + __WFI(); + } + } +#endif + + return backlight_pwm_set(val); +} void display_init_seq(void) { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14 @@ -287,6 +339,54 @@ void display_setup_fmc(void) { HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL); } +#ifdef FRAMEBUFFER +void display_setup_dma(void) { + // setup DMA for transferring framebuffer to display + + __HAL_RCC_GPDMA1_CLK_ENABLE(); + + /* USER CODE END GPDMA1_Init 1 */ + DMA_Handle.Instance = GPDMA1_Channel0; + DMA_Handle.XferCpltCallback = HAL_DMA_XferCpltCallback; + DMA_Handle.Init.Request = GPDMA1_REQUEST_HASH_IN; + DMA_Handle.Init.BlkHWRequest = DMA_BREQ_SINGLE_BURST; + DMA_Handle.Init.Direction = DMA_MEMORY_TO_MEMORY; + DMA_Handle.Init.SrcInc = DMA_SINC_INCREMENTED; + DMA_Handle.Init.DestInc = DMA_DINC_FIXED; + DMA_Handle.Init.SrcDataWidth = DMA_SRC_DATAWIDTH_BYTE; + DMA_Handle.Init.DestDataWidth = DMA_DEST_DATAWIDTH_BYTE; + DMA_Handle.Init.Priority = DMA_LOW_PRIORITY_HIGH_WEIGHT; + DMA_Handle.Init.SrcBurstLength = 1; + DMA_Handle.Init.DestBurstLength = 1; + DMA_Handle.Init.TransferAllocatedPort = + DMA_SRC_ALLOCATED_PORT1 | DMA_DEST_ALLOCATED_PORT0; + DMA_Handle.Init.TransferEventMode = DMA_TCEM_BLOCK_TRANSFER; + DMA_Handle.Init.Mode = DMA_NORMAL; + HAL_DMA_Init(&DMA_Handle); + HAL_DMA_ConfigChannelAttributes(&DMA_Handle, DMA_CHANNEL_SEC | + DMA_CHANNEL_SRC_SEC | + DMA_CHANNEL_DEST_SEC); + + HAL_NVIC_SetPriority(GPDMA1_Channel0_IRQn, IRQ_PRI_DMA, 0); + HAL_NVIC_EnableIRQ(GPDMA1_Channel0_IRQn); +} + +void display_setup_te_interrupt(void) { +#ifdef DISPLAY_TE_PIN + 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 +} +#endif + void display_init(void) { // init peripherals __HAL_RCC_GPIOE_CLK_ENABLE(); @@ -350,6 +450,13 @@ void display_init(void) { display_init_seq(); display_set_little_endian(); + + panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + +#ifdef FRAMEBUFFER + display_setup_dma(); + display_setup_te_interrupt(); +#endif } void display_reinit(void) { @@ -361,6 +468,7 @@ void display_reinit(void) { display_set_little_endian(); DISPLAY_ORIENTATION = 0; + panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); backlight_pwm_reinit(); @@ -373,25 +481,13 @@ void display_reinit(void) { lx154a2411_gamma(); } #endif -} -void display_sync(void) { -#ifdef DISPLAY_TE_PIN - uint32_t id = display_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)) { - } - } +#ifdef FRAMEBUFFER + display_setup_dma(); + display_setup_te_interrupt(); #endif } -void display_refresh(void) {} - void display_set_little_endian(void) { uint32_t id = display_identify(); if (id == DISPLAY_ID_GC9307) { @@ -430,8 +526,245 @@ const char *display_save(const char *prefix) { return NULL; } void display_clear_save(void) {} +#ifdef FRAMEBUFFER + +void display_pixeldata(uint16_t c) { + uint16_t *address = 0; + + if (act_frame_buffer == 0) { + address = PhysFrameBuffer1; + } else { + address = PhysFrameBuffer0; + } + + /* Get the rectangle start address */ + address += cursor_y * DISPLAY_RESX + cursor_x; + + *address = c; + + cursor_x++; + if (cursor_x > window_x1) { + cursor_x = window_x0; + cursor_y++; + } + if (cursor_y > window_y1) { + cursor_y = window_y0; + } +} + +void display_sync(void) {} + +void HAL_DMA_XferCpltCallback(DMA_HandleTypeDef *hdma) { + if (dma_transfer_remaining > 0xFFFF) { + dma_transfer_remaining -= 0xFFFF; + dma_data_transferred += 0xFFFF; + } else { + dma_data_transferred += dma_transfer_remaining; + dma_transfer_remaining = 0; + } + + if (dma_transfer_remaining > 0) { + uint32_t data_to_send = + dma_transfer_remaining > 0xFFFF ? 0xFFFF : dma_transfer_remaining; + + if (act_frame_buffer == 0) { + HAL_DMA_Start_IT( + hdma, + (uint32_t) & ((uint8_t *)PhysFrameBuffer0)[dma_data_transferred], + (uint32_t)DISPLAY_DATA_ADDRESS, data_to_send); + } else { + HAL_DMA_Start_IT( + hdma, + (uint32_t) & ((uint8_t *)PhysFrameBuffer1)[dma_data_transferred], + (uint32_t)DISPLAY_DATA_ADDRESS, data_to_send); + } + } +} + +void DISPLAY_TE_INTERRUPT_HANDLER(void) { + HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM); + + uint32_t data_to_send = DISPLAY_RESX * DISPLAY_RESY * 2 > 0xFFFF + ? 0xFFFF + : DISPLAY_RESX * DISPLAY_RESY * 2; + + if (act_frame_buffer == 1) { + HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)PhysFrameBuffer1, + (uint32_t)DISPLAY_DATA_ADDRESS, data_to_send); + + } else { + HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)PhysFrameBuffer0, + (uint32_t)DISPLAY_DATA_ADDRESS, data_to_send); + } + + __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); +} + +void GPDMA1_Channel0_IRQHandler(void) { + if ((DMA_Handle.Instance->CSR & DMA_CSR_TCF) == 0) { + // error, abort the transfer and allow the next one to start + dma_data_transferred = 0; + dma_transfer_remaining = 0; + } + + HAL_DMA_IRQHandler(&DMA_Handle); +} + +void display_refresh(void) { + while (dma_transfer_remaining > 0) { + __WFI(); + } + + if (is_mode_handler()) { + // 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 (act_frame_buffer == 0) { + act_frame_buffer = 1; + for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { + // 2 bytes per pixel because we're using RGB 5-6-5 format + DATA_TRANSFER(PhysFrameBuffer1[i]); + } + memcpy(PhysFrameBuffer0, PhysFrameBuffer1, sizeof(PhysFrameBuffer1)); + + } else { + act_frame_buffer = 0; + for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { + // 2 bytes per pixel because we're using RGB 5-6-5 format + DATA_TRANSFER(PhysFrameBuffer0[i]); + } + memcpy(PhysFrameBuffer1, PhysFrameBuffer0, sizeof(PhysFrameBuffer1)); + } + } else { + dma_transfer_remaining = DISPLAY_RESX * DISPLAY_RESY * 2; + dma_data_transferred = 0; + + if (act_frame_buffer == 0) { + act_frame_buffer = 1; + + memcpy(PhysFrameBuffer0, PhysFrameBuffer1, sizeof(PhysFrameBuffer1)); + + __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); + svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + } else { + act_frame_buffer = 0; + memcpy(PhysFrameBuffer1, PhysFrameBuffer0, sizeof(PhysFrameBuffer1)); + + __HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN); + svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM); + } + } +} + +void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + window_x0 = x0; + window_y0 = y0; + window_x1 = x1; + window_y1 = y1; + cursor_x = x0; + cursor_y = y0; +} + +uint8_t *display_get_wr_addr(void) { + uint32_t address = 0; + + if (act_frame_buffer == 0) { + address = (uint32_t)PhysFrameBuffer1; + } else { + address = (uint32_t)PhysFrameBuffer0; + } + + /* Get the rectangle start address */ + address = (address + (2 * (cursor_y * DISPLAY_RESX + cursor_x))); + + return (uint8_t *)address; +} + +uint32_t *display_get_fb_addr(void) { + uint32_t address = 0; + + if (act_frame_buffer == 0) { + address = (uint32_t)PhysFrameBuffer1; + } else { + address = (uint32_t)PhysFrameBuffer0; + } + + return (uint32_t *)address; +} +uint16_t display_get_window_width(void) { return window_x1 - window_x0 + 1; } + +uint16_t display_get_window_height(void) { return window_y1 - window_y0 + 1; } + +void display_shift_window(uint16_t pixels) { + uint16_t w = display_get_window_width(); + uint16_t h = display_get_window_height(); + + uint16_t line_rem = w - (cursor_x - window_x0); + + if (pixels < line_rem) { + cursor_x += pixels; + return; + } + + // start of next line + pixels = pixels - line_rem; + cursor_x = window_x0; + cursor_y++; + + // add the rest of pixels + cursor_y = window_y0 + (((cursor_y - window_y0) + (pixels / w)) % h); + cursor_x += pixels % w; +} + +uint16_t display_get_window_offset(void) { + return DISPLAY_RESX - display_get_window_width(); +} + +void display_efficient_clear(void) { + memzero(PhysFrameBuffer1, sizeof(PhysFrameBuffer1)); + memzero(PhysFrameBuffer0, sizeof(PhysFrameBuffer0)); +} + +void display_finish_actions(void) { + while (dma_transfer_remaining > 0) { + __WFI(); + } +} +#else +// NOT FRAMEBUFFER + +void display_pixeldata(uint16_t c) { PIXELDATA(c); } + +void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { + panel_set_window(x0, y0, x1, y1); +} + +void display_sync(void) { +#ifdef DISPLAY_TE_PIN + uint32_t id = display_identify(); + if (id && (id != DISPLAY_ID_GC9307)) { + // synchronize with the panel synchronization signal + // in order to avoid visual tearing effects + while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) + ; + while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) + ; + } +#endif +} + +void display_refresh(void) {} + uint8_t *display_get_wr_addr(void) { return (uint8_t *)DISPLAY_DATA_ADDRESS; } uint16_t display_get_window_offset(void) { return 0; } void display_shift_window(uint16_t pixels) {} + +void display_finish_actions(void) {} + +#endif diff --git a/core/embed/trezorhal/stm32f4/displays/st7789v.h b/core/embed/trezorhal/stm32f4/displays/st7789v.h index 9590a57cd8..f3f1958714 100644 --- a/core/embed/trezorhal/stm32f4/displays/st7789v.h +++ b/core/embed/trezorhal/stm32f4/displays/st7789v.h @@ -24,12 +24,33 @@ typedef struct { #error "Unsupported display interface" #endif +#define DISP_MEM_TYPE uint8_t + extern __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS; extern __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS; #define CMD(X) (*DISPLAY_CMD_ADDRESS = (X)) #define DATA(X) (*DISPLAY_DATA_ADDRESS = (X)) +void display_set_little_endian(void); +void display_set_big_endian(void); +void display_set_slow_pwm(void); + +#ifdef FRAMEBUFFER +#define DISPLAY_FRAMEBUFFER_WIDTH DISPLAY_RESX +#define DISPLAY_FRAMEBUFFER_HEIGHT DISPLAY_RESY + +#define DISPLAY_EFFICIENT_CLEAR 1 + +static inline void display_pixel(uint8_t *fb, int16_t x, int16_t y, + uint16_t color) { + uint32_t p = 2 * (y * DISPLAY_FRAMEBUFFER_WIDTH + x); + *((uint16_t *)(fb + p)) = color; +} +void display_efficient_clear(void); + +#else + #ifdef USE_DISP_I8080_16BIT_DW #define PIXELDATA(X) DATA(X) #elif USE_DISP_I8080_8BIT_DW @@ -38,8 +59,6 @@ extern __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS; DATA((X) >> 8) #endif -void display_set_little_endian(void); -void display_set_big_endian(void); -void display_set_slow_pwm(void); +#endif #endif //_ST7789V_H diff --git a/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c b/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c index 897958af75..a9561b756d 100644 --- a/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c +++ b/core/embed/trezorhal/stm32f4/displays/ug-2828tswig01.c @@ -368,3 +368,5 @@ void display_reinit(void) {} const char *display_save(const char *prefix) { return NULL; } void display_clear_save(void) {} + +void display_finish_actions(void) {} diff --git a/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c b/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c index ca894efffb..29f371cd6b 100644 --- a/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c +++ b/core/embed/trezorhal/stm32f4/displays/vg-2864ksweg01.c @@ -297,3 +297,5 @@ void display_refresh(void) { const char *display_save(const char *prefix) { return NULL; } void display_clear_save(void) {} + +void display_finish_actions(void) {} diff --git a/core/embed/trezorhal/stm32u5/common.c b/core/embed/trezorhal/stm32u5/common.c index dfe50cfcd8..9b081c446d 100644 --- a/core/embed/trezorhal/stm32u5/common.c +++ b/core/embed/trezorhal/stm32u5/common.c @@ -204,7 +204,7 @@ void collect_hw_entropy(void) { // this function resets settings changed in one layer (bootloader/firmware), // which might be incompatible with the other layers older versions, // where this setting might be unknown -void ensure_compatible_settings(void) {} +void ensure_compatible_settings(void) { display_finish_actions(); } void show_wipe_code_screen(void) { error_uni("WIPE CODE ENTERED", "All data has been erased from the device", diff --git a/core/embed/trezorhal/stm32u5/displays/dsi.c b/core/embed/trezorhal/stm32u5/displays/dsi.c index cf31cf6409..8e44fabb41 100644 --- a/core/embed/trezorhal/stm32u5/displays/dsi.c +++ b/core/embed/trezorhal/stm32u5/displays/dsi.c @@ -1728,3 +1728,5 @@ const char *display_save(const char *prefix) { return NULL; } void display_clear_save(void) {} void display_pixeldata_dirty(void) {} + +void display_finish_actions(void) {} diff --git a/core/embed/trezorhal/unix/display-unix.c b/core/embed/trezorhal/unix/display-unix.c index d60a18d72b..85fccca349 100644 --- a/core/embed/trezorhal/unix/display-unix.c +++ b/core/embed/trezorhal/unix/display-unix.c @@ -345,3 +345,5 @@ void display_clear_save(void) { } uint8_t *display_get_wr_addr(void) { return (uint8_t *)DISPLAY_DATA_ADDRESS; } + +void display_finish_actions(void) {} diff --git a/core/site_scons/boards/stm32f4_common.py b/core/site_scons/boards/stm32f4_common.py index c9d83588cf..654f043819 100644 --- a/core/site_scons/boards/stm32f4_common.py +++ b/core/site_scons/boards/stm32f4_common.py @@ -75,7 +75,7 @@ def stm32f4_common_files(env, defines, sources, paths): "-DSTM32_HAL_H=;" "-DSTM32F4;" "-DFLASH_BLOCK_WORDS=1;" - "-DFLASH_BIT_ACCESS=1" + "-DFLASH_BIT_ACCESS=1;" ) env.get("ENV")["SUFFIX"] = "stm32f4" diff --git a/core/site_scons/boards/stm32u5_common.py b/core/site_scons/boards/stm32u5_common.py index 2ddf6c808d..1c274faf8d 100644 --- a/core/site_scons/boards/stm32u5_common.py +++ b/core/site_scons/boards/stm32u5_common.py @@ -22,6 +22,7 @@ def stm32u5_common_files(env, defines, sources, paths): "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_dma.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_dma_ex.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_dsi.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_exti.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_flash.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_flash_ex.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_gfxmmu.c", @@ -87,7 +88,7 @@ def stm32u5_common_files(env, defines, sources, paths): "-I../../vendor/cmsis_5/CMSIS/Core/Include;" "-DSTM32_HAL_H=;" "-DSTM32U5;" - "-DFLASH_BLOCK_WORDS=4" + "-DFLASH_BLOCK_WORDS=4;" ) env.get("ENV")["SUFFIX"] = "stm32u5" diff --git a/core/site_scons/boards/trezor_t3t1_v4.py b/core/site_scons/boards/trezor_t3t1_v4.py index 7e18d2586d..6ed533eb91 100644 --- a/core/site_scons/boards/trezor_t3t1_v4.py +++ b/core/site_scons/boards/trezor_t3t1_v4.py @@ -17,6 +17,8 @@ def configure( hw_model = get_hw_model_as_number("T3T1") hw_revision = 0 features_available.append("disp_i8080_8bit_dw") + features_available.append("framebuffer") + defines += ["FRAMEBUFFER"] mcu = "STM32U585xx" linker_script = "stm32u58" @@ -106,4 +108,8 @@ def configure( defs = env.get("CPPDEFINES_IMPLICIT") defs += ["__ARM_FEATURE_CMSE=3"] + rust_defs = env.get("ENV")["RUST_INCLUDES"] + rust_defs += "-DFRAMEBUFFER;" + env.get("ENV")["RUST_INCLUDES"] = rust_defs + return features_available