1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-04 13:38:28 +00:00

Compare commits

...

7 Commits

Author SHA1 Message Date
TychoVrahe
6ea797578e
Merge ee77086f92 into ef02c4de5d 2024-12-03 14:10:41 +01:00
matejcik
ef02c4de5d feat(core): introduce storage insecure mode
reduces the number of PIN iterations and avoids erasing the other
storage bank -- if a test ever overruns, it will probably RSOD out, but
that's unlikely to happen
2024-12-03 11:02:17 +01:00
matejcik
835f7087c6 build(core): correctly propagate DISABLE_OPTIGA to kernel 2024-12-03 11:02:17 +01:00
matejcik
331e07b1e0 feat(core): disable animations in debug firmware by default
This makes it possible to run HW tests on the T3T1 where animations mess
things up. It also speeds up HW tests on other models slightly.

export TREZOR_DISABLE_ANIMATION=0 to build a debug firmware with
animations enabled
2024-12-03 11:02:17 +01:00
tychovrahe
ee77086f92 refactor(core): switch DISC2 display driver to universal LTDC DSI implementation
[no changelog]
2024-12-02 15:03:27 +01:00
tychovrahe
c52b026c37 feat(core): display driver for T3W1
[no changelog]

disp
2024-12-02 15:03:27 +01:00
tychovrahe
f9ff748a90 refactor(core): extract framebuffer queue for reuse
[no changelog]
2024-12-02 15:03:27 +01:00
34 changed files with 1643 additions and 2238 deletions

View File

@ -31,6 +31,7 @@ PYOPT ?= 1
BITCOIN_ONLY ?= 0
BOOTLOADER_QA ?= 0
BOOTLOADER_DEVEL ?= 0
DISABLE_OPTIGA ?= 0
TREZOR_MODEL ?= T
TREZOR_MEMPERF ?= 0
ADDRESS_SANITIZER ?= 0
@ -41,6 +42,8 @@ THP ?= 0
BENCHMARK ?= 0
TREZOR_EMULATOR_DEBUGGABLE ?= 0
QUIET_MODE ?= 0
TREZOR_DISABLE_ANIMATION ?= $(if $(filter 0,$(PYOPT)),1,0)
STORAGE_INSECURE_TESTING_MODE ?= 0
# OpenOCD interface default. Alternative: ftdi/olimex-arm-usb-tiny-h
OPENOCD_INTERFACE ?= stlink
@ -142,7 +145,9 @@ SCONS_VARS = \
PRODUCTION="$(PRODUCTION)" \
PYOPT="$(PYOPT)" \
QUIET_MODE="$(QUIET_MODE)" \
STORAGE_INSECURE_TESTING_MODE="$(STORAGE_INSECURE_TESTING_MODE)" \
THP="$(THP)" \
TREZOR_DISABLE_ANIMATION="$(TREZOR_DISABLE_ANIMATION)" \
TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \
TREZOR_EMULATOR_DEBUGGABLE=$(TREZOR_EMULATOR_DEBUGGABLE) \
TREZOR_MEMPERF="$(TREZOR_MEMPERF)" \

View File

@ -18,6 +18,14 @@ HW_REVISION = ARGUMENTS.get('HW_REVISION', None)
THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol
MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL)
BENCHMARK = ARGUMENTS.get('BENCHMARK', '0') == '1'
DISABLE_ANIMATION = ARGUMENTS.get('TREZOR_DISABLE_ANIMATION', '0') == '1'
STORAGE_INSECURE_TESTING_MODE = ARGUMENTS.get('STORAGE_INSECURE_TESTING_MODE', '0') == '1'
if STORAGE_INSECURE_TESTING_MODE and PRODUCTION:
raise RuntimeError("STORAGE_INSECURE_TESTING_MODE cannot be used in production")
if STORAGE_INSECURE_TESTING_MODE:
DISABLE_OPTIGA = True
PYOPT = "0"
if BENCHMARK and PYOPT != '0':
print("BENCHMARK=1 works only with PYOPT=0.")
@ -30,7 +38,9 @@ FEATURE_FLAGS = {
}
FEATURES_WANTED = ["input", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"]
if DISABLE_OPTIGA and PYOPT == '0':
if DISABLE_OPTIGA:
if PYOPT != '0':
raise RuntimeError("DISABLE_OPTIGA requires PYOPT=0")
FEATURES_WANTED.remove("optiga")
CCFLAGS_MOD = ''
@ -69,6 +79,7 @@ CPPDEFINES_MOD += [
('USE_CARDANO', '1' if EVERYTHING else '0'),
('USE_NEM', '1' if (EVERYTHING and TREZOR_MODEL == "T") else '0'),
('USE_EOS', '1' if (EVERYTHING and TREZOR_MODEL == "T") else '0'),
('DISABLE_ANIMATION', '1' if DISABLE_ANIMATION else '0'),
]
SOURCE_MOD += [
'embed/upymod/trezorobj.c',
@ -367,6 +378,9 @@ if THP:
'vendor/trezor-crypto/elligator2.c',
]
if STORAGE_INSECURE_TESTING_MODE:
CPPDEFINES_MOD += ['STORAGE_INSECURE_TESTING_MODE']
ui.init_ui(TREZOR_MODEL, "firmware", CPPDEFINES_MOD, SOURCE_MOD, RUST_UI_FEATURES)
SOURCE_QSTR = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED
@ -873,6 +887,14 @@ elif 'STM32U5G9xx' in CPPDEFINES_HAL or 'STM32U585xx' in CPPDEFINES_HAL:
else:
raise Exception("Unknown MCU")
if STORAGE_INSECURE_TESTING_MODE:
INSECURE_TESTING_MODE_STR = """
#########################################################
# STORAGE_INSECURE_TESTING_MODE enabled, DO NOT USE #
#########################################################
"""
action_bin.append(INSECURE_TESTING_MODE_STR)
program_bin = env.Command(
target='firmware.bin',
source=program_elf,

View File

@ -16,6 +16,13 @@ DISABLE_OPTIGA = ARGUMENTS.get('DISABLE_OPTIGA', '0') == '1'
HW_REVISION = ARGUMENTS.get('HW_REVISION', None)
THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol
STORAGE_INSECURE_TESTING_MODE = ARGUMENTS.get('STORAGE_INSECURE_TESTING_MODE', '0') == '1'
if STORAGE_INSECURE_TESTING_MODE and PRODUCTION:
raise RuntimeError("STORAGE_INSECURE_TESTING_MODE cannot be used in production")
if STORAGE_INSECURE_TESTING_MODE:
DISABLE_OPTIGA = True
PYOPT = "0"
FEATURE_FLAGS = {
"RDI": True,
"SECP256K1_ZKP": True, # required for trezor.crypto.curve.bip340 (BIP340/Taproot)
@ -24,7 +31,10 @@ FEATURE_FLAGS = {
}
FEATURES_WANTED = ["input", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"]
if DISABLE_OPTIGA and PYOPT == '0':
if DISABLE_OPTIGA:
# TODO use PYOPT instead of PRODUCTION, same as in firmware, blocked on #4253
if PRODUCTION:
raise RuntimeError("DISABLE_OPTIGA requires non-production build")
FEATURES_WANTED.remove("optiga")
CCFLAGS_MOD = ''
@ -235,6 +245,8 @@ if THP:
'vendor/trezor-crypto/elligator2.c',
]
if STORAGE_INSECURE_TESTING_MODE:
CPPDEFINES_MOD += ['STORAGE_INSECURE_TESTING_MODE']
env = Environment(
ENV=os.environ,
@ -411,6 +423,14 @@ action_bin=[
'$CP $TARGET ' + BINARY_NAME,
]
if STORAGE_INSECURE_TESTING_MODE:
INSECURE_TESTING_MODE_STR = """
#########################################################
# STORAGE_INSECURE_TESTING_MODE enabled, DO NOT USE #
#########################################################
"""
action_bin.append(INSECURE_TESTING_MODE_STR)
program_bin = env.Command(
target='kernel.bin',
source=program_elf,

View File

@ -0,0 +1,129 @@
#ifdef KERNEL_MODE
#include "fb_queue.h"
int16_t fb_queue_get_for_copy(volatile frame_buffer_queue_t *queue) {
if (queue->entry[queue->wix] != FB_STATE_PREPARING) {
// No refresh needed as the frame buffer is not in
// the state to be copied to the display
return -1;
}
return queue->wix;
}
int16_t fb_queue_get_for_write(volatile frame_buffer_queue_t *queue) {
frame_buffer_state_t state;
// We have to wait if the buffer was passed for copying
// to the interrupt handler
do {
state = queue->entry[queue->wix];
} while (state == FB_STATE_READY || state == FB_STATE_COPYING);
queue->entry[queue->wix] = FB_STATE_PREPARING;
return queue->wix;
}
int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue) {
if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
return -1;
}
switch (queue->entry[queue->rix]) {
case FB_STATE_EMPTY:
case FB_STATE_PREPARING:
// No new frame queued
case FB_STATE_COPYING:
// Currently we are copying a data to the display.
return -1;
break;
case FB_STATE_READY:
// Now it's proper time to copy the data to the display
queue->entry[queue->rix] = FB_STATE_COPYING;
return queue->rix;
// NOTE: when copying is done, this queue slot is marked empty
break;
default:
// This is an invalid state, and we should never get here
return -1;
break;
}
}
bool fb_queue_set_done(volatile frame_buffer_queue_t *queue) {
if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
return false;
}
if (queue->entry[queue->rix] == FB_STATE_COPYING) {
queue->entry[queue->rix] = FB_STATE_EMPTY;
queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT;
return true;
}
return false;
}
bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue) {
if (queue->rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
return false;
}
if (queue->entry[queue->rix] == FB_STATE_COPYING) {
if (queue->aix >= 0) {
queue->entry[queue->aix] = FB_STATE_EMPTY;
}
queue->aix = queue->rix;
queue->rix = (queue->rix + 1) % FRAME_BUFFER_COUNT;
return true;
}
return false;
}
bool fb_queue_set_ready_for_transfer(volatile frame_buffer_queue_t *queue) {
if (queue->wix >= FRAME_BUFFER_COUNT) {
// This is an invalid state, and we should never get here
return false;
}
if (queue->entry[queue->rix] == FB_STATE_PREPARING) {
queue->entry[queue->rix] = FB_STATE_READY;
queue->wix = (queue->wix + 1) % FRAME_BUFFER_COUNT;
return true;
}
return false;
}
void fb_queue_reset(volatile frame_buffer_queue_t *queue) {
// Reset the buffer queue so we can eventually continue
// safely in thread mode
queue->wix = 0;
queue->rix = 0;
for (int i = 0; i < FRAME_BUFFER_COUNT; i++) {
queue->entry[i] = FB_STATE_EMPTY;
}
}
bool fb_queue_is_processed(volatile frame_buffer_queue_t *queue) {
for (int i = 0; i < FRAME_BUFFER_COUNT; i++) {
frame_buffer_state_t state = queue->entry[i];
if (state == FB_STATE_READY ||
(state == FB_STATE_COPYING && i != queue->aix)) {
return false;
}
}
return true;
}
#endif

View File

@ -0,0 +1,73 @@
/*
* 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/>.
*/
#pragma once
#include <trezor_types.h>
// Number of frame buffers used (1 or 2)
// If 1 buffer is selected, some animations may not
// be so smooth but the memory usage is lower.
#define FRAME_BUFFER_COUNT 2
// Each frame buffer can be in one of the following states:
typedef enum {
// The frame buffer is empty and can be written to
FB_STATE_EMPTY = 0,
// The frame buffer pass passed to application
FB_STATE_PREPARING = 1,
// The frame buffer was written to and is ready
// to be copied to the display
FB_STATE_READY = 2,
// The frame buffer is currently being copied to
// the display
FB_STATE_COPYING = 3,
} frame_buffer_state_t;
typedef struct {
// Queue entries
volatile frame_buffer_state_t entry[FRAME_BUFFER_COUNT];
// Active index
// (accessed & updated in the context of the interrupt handlers
int16_t aix;
// Read index
// (accessed & updated in the context of the interrupt handlers
uint8_t rix;
// Write index
// (accessed & updated in context of the main thread)
uint8_t wix;
} frame_buffer_queue_t;
int16_t fb_queue_get_for_copy(volatile frame_buffer_queue_t *queue);
int16_t fb_queue_get_for_write(volatile frame_buffer_queue_t *queue);
int16_t fb_queue_get_for_transfer(volatile frame_buffer_queue_t *queue);
bool fb_queue_set_done(volatile frame_buffer_queue_t *queue);
bool fb_queue_set_switched(volatile frame_buffer_queue_t *queue);
bool fb_queue_set_ready_for_transfer(volatile frame_buffer_queue_t *queue);
void fb_queue_reset(volatile frame_buffer_queue_t *queue);
bool fb_queue_is_processed(volatile frame_buffer_queue_t *queue);

View File

@ -0,0 +1,404 @@
#include <trezor_bsp.h>
#include <trezor_model.h>
#include <trezor_rtl.h>
#include <io/display.h>
#ifdef KERNEL_MODE
#include <sys/irq.h>
#include <sys/mpu.h>
#include <sys/systick.h>
#ifdef USE_BACKLIGHT
#include "../backlight/backlight_pwm.h"
#endif
#include "display_internal.h"
display_driver_t g_display_driver = {
.initialized = false,
};
static void display_pll_init(void) {
RCC_PeriphCLKInitTypeDef PLL3InitPeriph = {0};
/* Start and configure PLL3 */
/* HSE = 16/32MHZ */
/* 16/32/(M=8) = 4MHz input (min) */
/* 4*(N=125) = 500MHz VCO (almost max) */
/* 500/(P=8) = 62.5 for DSI ie exactly the lane byte clock*/
PLL3InitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI | RCC_PERIPHCLK_LTDC;
PLL3InitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_PLL3;
PLL3InitPeriph.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3;
#if HSE_VALUE == 32000000
PLL3InitPeriph.PLL3.PLL3M = 8;
#elif HSE_VALUE == 16000000
PLL3InitPeriph.PLL3.PLL3M = 4;
#endif
PLL3InitPeriph.PLL3.PLL3N = 125;
PLL3InitPeriph.PLL3.PLL3P = 8;
PLL3InitPeriph.PLL3.PLL3Q = 8;
PLL3InitPeriph.PLL3.PLL3R = 24;
PLL3InitPeriph.PLL3.PLL3FRACN = 0;
PLL3InitPeriph.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0;
PLL3InitPeriph.PLL3.PLL3ClockOut = RCC_PLL3_DIVR | RCC_PLL3_DIVP;
PLL3InitPeriph.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
(void)HAL_RCCEx_PeriphCLKConfig(&PLL3InitPeriph);
}
static void display_dsi_init(void) {
display_driver_t *drv = &g_display_driver;
RCC_PeriphCLKInitTypeDef DSIPHYInitPeriph = {0};
DSI_PLLInitTypeDef PLLInit = {0};
DSI_PHY_TimerTypeDef PhyTimers = {0};
DSI_HOST_TimeoutTypeDef HostTimeouts = {0};
/* Enable DSI clock */
__HAL_RCC_DSI_CLK_ENABLE();
/* Switch to D-PHY source clock */
/* Enable the DSI host */
drv->hlcd_dsi.Instance = DSI;
__HAL_DSI_ENABLE(&drv->hlcd_dsi);
/* Enable the DSI PLL */
__HAL_DSI_PLL_ENABLE(&drv->hlcd_dsi);
HAL_Delay(1);
/* Enable the clock lane and the digital section of the D-PHY */
drv->hlcd_dsi.Instance->PCTLR |= (DSI_PCTLR_CKE | DSI_PCTLR_DEN);
/* Set the TX escape clock division factor */
drv->hlcd_dsi.Instance->CCR = 4;
HAL_Delay(1);
/* Config DSI Clock to DSI PHY */
DSIPHYInitPeriph.PeriphClockSelection = RCC_PERIPHCLK_DSI;
DSIPHYInitPeriph.DsiClockSelection = RCC_DSICLKSOURCE_DSIPHY;
(void)HAL_RCCEx_PeriphCLKConfig(&DSIPHYInitPeriph);
/* Reset the TX escape clock division factor */
drv->hlcd_dsi.Instance->CCR &= ~DSI_CCR_TXECKDIV;
/* Disable the DSI PLL */
__HAL_DSI_PLL_DISABLE(&drv->hlcd_dsi);
/* Disable the DSI host */
__HAL_DSI_DISABLE(&drv->hlcd_dsi);
/* DSI initialization */
drv->hlcd_dsi.Instance = DSI;
drv->hlcd_dsi.Init.AutomaticClockLaneControl = DSI_AUTO_CLK_LANE_CTRL_DISABLE;
/* We have 1 data lane at 500Mbps => lane byte clock at 500/8 = 62,5 MHZ */
/* We want TX escape clock at around 20MHz and under 20MHz so clock division
* is set to 4 */
drv->hlcd_dsi.Init.TXEscapeCkdiv = 4;
drv->hlcd_dsi.Init.NumberOfLanes = PANEL_DSI_LANES;
drv->hlcd_dsi.Init.PHYFrequencyRange = DSI_DPHY_FRANGE_450MHZ_510MHZ;
drv->hlcd_dsi.Init.PHYLowPowerOffset = 0;
#if HSE_VALUE == 32000000
PLLInit.PLLNDIV = 62;
#elif HSE_VALUE == 16000000
PLLInit.PLLNDIV = 125;
#endif
PLLInit.PLLIDF = 4;
PLLInit.PLLODF = 2;
PLLInit.PLLVCORange = DSI_DPHY_VCO_FRANGE_800MHZ_1GHZ;
PLLInit.PLLChargePump = DSI_PLL_CHARGE_PUMP_2000HZ_4400HZ;
PLLInit.PLLTuning = DSI_PLL_LOOP_FILTER_2000HZ_4400HZ;
HAL_DSI_Init(&drv->hlcd_dsi, &PLLInit);
HAL_DSI_SetGenericVCID(&drv->hlcd_dsi, 0);
/* Configure the DSI for Video mode */
drv->DSIVidCfg.VirtualChannelID = 0;
drv->DSIVidCfg.HSPolarity = DSI_HSYNC_ACTIVE_HIGH;
drv->DSIVidCfg.VSPolarity = DSI_VSYNC_ACTIVE_HIGH;
drv->DSIVidCfg.DEPolarity = DSI_DATA_ENABLE_ACTIVE_HIGH;
drv->DSIVidCfg.ColorCoding = DSI_RGB888;
drv->DSIVidCfg.Mode = PANEL_DSI_MODE;
drv->DSIVidCfg.PacketSize = LCD_WIDTH;
drv->DSIVidCfg.NullPacketSize = 0xFFFU;
drv->DSIVidCfg.HorizontalSyncActive = HSYNC * 3;
drv->DSIVidCfg.HorizontalBackPorch = HBP * 3;
drv->DSIVidCfg.HorizontalLine = (HACT + HSYNC + HBP + HFP) * 3;
drv->DSIVidCfg.VerticalSyncActive = VSYNC;
drv->DSIVidCfg.VerticalBackPorch = VBP;
drv->DSIVidCfg.VerticalFrontPorch = VFP;
drv->DSIVidCfg.VerticalActive = VACT;
drv->DSIVidCfg.LPCommandEnable = DSI_LP_COMMAND_ENABLE;
drv->DSIVidCfg.LPLargestPacketSize = 64;
/* Specify for each region of the video frame, if the transmission of command
* in LP mode is allowed in this region */
/* while streaming is active in video mode */
drv->DSIVidCfg.LPHorizontalFrontPorchEnable = DSI_LP_HFP_ENABLE;
drv->DSIVidCfg.LPHorizontalBackPorchEnable = DSI_LP_HBP_ENABLE;
drv->DSIVidCfg.LPVerticalActiveEnable = DSI_LP_VACT_ENABLE;
drv->DSIVidCfg.LPVerticalFrontPorchEnable = DSI_LP_VFP_ENABLE;
drv->DSIVidCfg.LPVerticalBackPorchEnable = DSI_LP_VBP_ENABLE;
drv->DSIVidCfg.LPVerticalSyncActiveEnable = DSI_LP_VSYNC_ENABLE;
drv->DSIVidCfg.FrameBTAAcknowledgeEnable = DSI_FBTAA_ENABLE;
drv->DSIVidCfg.LooselyPacked = DSI_LOOSELY_PACKED_DISABLE;
/* Drive the display */
HAL_DSI_ConfigVideoMode(&drv->hlcd_dsi, &drv->DSIVidCfg);
/*********************/
/* LCD configuration */
/*********************/
PhyTimers.ClockLaneHS2LPTime = 11;
PhyTimers.ClockLaneLP2HSTime = 40;
PhyTimers.DataLaneHS2LPTime = 12;
PhyTimers.DataLaneLP2HSTime = 23;
PhyTimers.DataLaneMaxReadTime = 0;
PhyTimers.StopWaitTime = 7;
HAL_DSI_ConfigPhyTimer(&drv->hlcd_dsi, &PhyTimers);
HostTimeouts.TimeoutCkdiv = 1;
HostTimeouts.HighSpeedTransmissionTimeout = 0;
HostTimeouts.LowPowerReceptionTimeout = 0;
HostTimeouts.HighSpeedReadTimeout = 0;
HostTimeouts.LowPowerReadTimeout = 0;
HostTimeouts.HighSpeedWriteTimeout = 0;
HostTimeouts.HighSpeedWritePrespMode = 0;
HostTimeouts.LowPowerWriteTimeout = 0;
HostTimeouts.BTATimeout = 0;
HAL_DSI_ConfigHostTimeouts(&drv->hlcd_dsi, &HostTimeouts);
HAL_DSI_ConfigFlowControl(&drv->hlcd_dsi, DSI_FLOW_CONTROL_BTA);
/* Enable the DSI host */
__HAL_DSI_ENABLE(&drv->hlcd_dsi);
}
void display_ltdc_config_layer(LTDC_HandleTypeDef *hltdc, uint32_t fb_addr) {
LTDC_LayerCfgTypeDef LayerCfg = {0};
/* LTDC layer configuration */
LayerCfg.WindowX0 = 0;
LayerCfg.WindowX1 = LCD_WIDTH;
LayerCfg.WindowY0 = LCD_Y_OFFSET;
LayerCfg.WindowY1 = LCD_HEIGHT + LCD_Y_OFFSET;
LayerCfg.PixelFormat = PANEL_LTDC_PIXEL_FORMAT;
LayerCfg.Alpha = 0xFF; /* NU default value */
LayerCfg.Alpha0 = 0; /* NU default value */
LayerCfg.BlendingFactor1 =
LTDC_BLENDING_FACTOR1_PAxCA; /* Not Used: default value */
LayerCfg.BlendingFactor2 =
LTDC_BLENDING_FACTOR2_PAxCA; /* Not Used: default value */
LayerCfg.FBStartAdress = fb_addr;
LayerCfg.ImageWidth =
FRAME_BUFFER_PIXELS_PER_LINE; /* Number of pixels per line in virtual
frame buffer */
LayerCfg.ImageHeight = LCD_HEIGHT;
LayerCfg.Backcolor.Red = 0; /* Not Used: default value */
LayerCfg.Backcolor.Green = 0; /* Not Used: default value */
LayerCfg.Backcolor.Blue = 0; /* Not Used: default value */
LayerCfg.Backcolor.Reserved = 0xFF;
HAL_LTDC_ConfigLayer(hltdc, &LayerCfg, LTDC_LAYER_1);
}
void display_ltdc_init(void) {
display_driver_t *drv = &g_display_driver;
__HAL_RCC_LTDC_CLK_ENABLE();
/* LTDC initialization */
drv->hlcd_ltdc.Instance = LTDC;
drv->hlcd_ltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
drv->hlcd_ltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
drv->hlcd_ltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
drv->hlcd_ltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
drv->hlcd_ltdc.Init.HorizontalSync = HSYNC - 1;
drv->hlcd_ltdc.Init.AccumulatedHBP = HSYNC + HBP - 1;
drv->hlcd_ltdc.Init.AccumulatedActiveW = HACT + HBP + HSYNC - 1;
drv->hlcd_ltdc.Init.TotalWidth = HACT + HBP + HFP + HSYNC - 1;
drv->hlcd_ltdc.Init.Backcolor.Red = 0; /* Not used default value */
drv->hlcd_ltdc.Init.Backcolor.Green = 0; /* Not used default value */
drv->hlcd_ltdc.Init.Backcolor.Blue = 0; /* Not used default value */
drv->hlcd_ltdc.Init.Backcolor.Reserved = 0xFF;
HAL_LTDCEx_StructInitFromVideoConfig(&drv->hlcd_ltdc, &drv->DSIVidCfg);
HAL_LTDC_Init(&drv->hlcd_ltdc);
display_ltdc_config_layer(&drv->hlcd_ltdc, display_fb_get_initial_addr());
}
void display_set_fb(uint32_t fb_addr) {
display_driver_t *drv = &g_display_driver;
display_ltdc_config_layer(&drv->hlcd_ltdc, fb_addr);
}
// Fully initializes the display controller.
void display_init(display_content_mode_t mode) {
display_driver_t *drv = &g_display_driver;
GPIO_InitTypeDef GPIO_InitStructure = {0};
__HAL_RCC_DSI_FORCE_RESET();
__HAL_RCC_LTDC_FORCE_RESET();
#ifdef DISPLAY_PWREN_PIN
DISPLAY_PWREN_CLK_ENA();
HAL_GPIO_WritePin(DISPLAY_PWREN_PORT, DISPLAY_PWREN_PIN, GPIO_PIN_RESET);
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
GPIO_InitStructure.Pin = DISPLAY_PWREN_PIN;
HAL_GPIO_Init(DISPLAY_PWREN_PORT, &GPIO_InitStructure);
#endif
#ifdef DISPLAY_RESET_PIN
DISPLAY_RESET_CLK_ENA();
HAL_GPIO_WritePin(GPIOE, DISPLAY_RESET_PIN, GPIO_PIN_RESET);
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
GPIO_InitStructure.Pin = DISPLAY_RESET_PIN;
HAL_GPIO_Init(DISPLAY_RESET_PORT, &GPIO_InitStructure);
systick_delay_ms(10);
HAL_GPIO_WritePin(DISPLAY_RESET_PORT, DISPLAY_RESET_PIN, GPIO_PIN_SET);
systick_delay_ms(120);
#endif
#ifdef DISPLAY_BACKLIGHT_PIN
DISPLAY_BACKLIGHT_CLK_ENABLE();
/* Configure LCD Backlight Pin */
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
GPIO_InitStructure.Pull = GPIO_PULLUP;
GPIO_InitStructure.Pin = DISPLAY_BACKLIGHT_PIN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(DISPLAY_BACKLIGHT_PORT, &GPIO_InitStructure);
#endif
#ifdef USE_BACKLIGHT
backlight_pwm_init(BACKLIGHT_RESET);
#endif
display_fb_clear();
__HAL_RCC_LTDC_RELEASE_RESET();
__HAL_RCC_DSI_RELEASE_RESET();
#ifdef DISPLAY_GFXMMU
display_gfxmmu_init(drv);
#endif
display_pll_init();
display_dsi_init();
display_ltdc_init();
/* Start DSI */
HAL_DSI_Start(&drv->hlcd_dsi);
panel_init(drv);
HAL_LTDC_ProgramLineEvent(&drv->hlcd_ltdc, LCD_HEIGHT);
/* Enable LTDC interrupt */
NVIC_SetPriority(LTDC_IRQn, IRQ_PRI_NORMAL);
NVIC_EnableIRQ(LTDC_IRQn);
NVIC_SetPriority(LTDC_ER_IRQn, IRQ_PRI_NORMAL);
NVIC_EnableIRQ(LTDC_ER_IRQn);
__HAL_LTDC_ENABLE_IT(&drv->hlcd_ltdc, LTDC_IT_LI | LTDC_IT_FU | LTDC_IT_TE);
drv->initialized = true;
}
int display_set_backlight(int level) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return 0;
}
#ifdef USE_BACKLIGHT
if (level > backlight_pwm_get()) {
display_ensure_refreshed();
}
return backlight_pwm_set(level);
#else
// Just emulation, not doing anything
drv->backlight_level = level;
return level;
#endif
}
int display_get_backlight(void) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return 0;
}
#ifdef USE_BACKLIGHT
return backlight_pwm_get();
#else
return drv->backlight_level;
#endif
}
int display_set_orientation(int angle) { return angle; }
int display_get_orientation(void) { return 0; }
void LTDC_IRQHandler(void) {
IRQ_LOG_ENTER();
mpu_mode_t mode = mpu_reconfig(MPU_MODE_DEFAULT);
display_driver_t *drv = &g_display_driver;
if (drv->hlcd_ltdc.State != HAL_LTDC_STATE_RESET) {
HAL_LTDC_IRQHandler(&drv->hlcd_ltdc);
} else {
LTDC->ICR = 0x3F;
}
mpu_restore(mode);
IRQ_LOG_EXIT();
}
void LTDC_ER_IRQHandler(void) {
IRQ_LOG_ENTER();
mpu_mode_t mode = mpu_reconfig(MPU_MODE_DEFAULT);
display_driver_t *drv = &g_display_driver;
if (drv->hlcd_ltdc.State != HAL_LTDC_STATE_RESET) {
HAL_LTDC_IRQHandler(&drv->hlcd_ltdc);
} else {
LTDC->ICR = 0x3F;
}
mpu_restore(mode);
IRQ_LOG_EXIT();
}
void display_deinit(display_content_mode_t mode) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}
// todo
NVIC_DisableIRQ(LTDC_IRQn);
NVIC_DisableIRQ(LTDC_ER_IRQn);
}
#endif

View File

@ -0,0 +1,238 @@
/*
* 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/>.
*/
#ifdef KERNEL_MODE
#include <trezor_bsp.h>
#include <trezor_model.h>
#include <trezor_rtl.h>
#include <io/display.h>
#include <sys/mpu.h>
#include <sys/trustzone.h>
#include "display_internal.h"
#define ALIGNED_PHYSICAL_FRAME_BUFFER_SIZE \
ALIGN_UP_CONST(PHYSICAL_FRAME_BUFFER_SIZE, PHYSICAL_FRAME_BUFFER_ALIGNMENT)
// Physical frame buffers in internal SRAM memory.
// Both frame buffers layers in the fixed addresses that
// are shared between bootloaders and the firmware.
__attribute__((section(".fb1"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_0[ALIGNED_PHYSICAL_FRAME_BUFFER_SIZE];
#if (FRAME_BUFFER_COUNT > 1)
__attribute__((section(".fb2"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_1[ALIGNED_PHYSICAL_FRAME_BUFFER_SIZE];
#endif
#ifdef USE_TRUSTZONE
void display_set_unpriv_access(bool unpriv) {
// To allow unprivileged access both GFXMMU virtual buffers area and
// underlying SRAM region must be configured as unprivileged.
// Order of GFXMMU and SRAM unprivileged access configuration is important
// to avoid the situation the virtual frame buffer has lower privileges
// than underlying frame buffer in physical memory so LTDC could not
// refresh the display properly.
#ifdef DISPLAY_GFXMMU
if (!unpriv) {
tz_set_gfxmmu_unpriv(unpriv);
}
#endif
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_0,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_1,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
#ifdef DISPLAY_GFXMMU
if (unpriv) {
tz_set_gfxmmu_unpriv(unpriv);
}
#endif
#ifdef USE_DMA2D
tz_set_dma2d_unpriv(unpriv);
#endif
}
#endif // USE_TRUSTZONE
// Returns the pointer to the physical frame buffer (0.. FRAME_BUFFER_COUNT-1)
// Returns NULL if the framebuffer index is out of range.
static uint8_t *get_fb_ptr(int16_t index) {
#ifdef DISPLAY_GFXMMU
if (index == 0) {
return (uint8_t *)GFXMMU_VIRTUAL_BUFFER0_BASE_S;
#if (FRAME_BUFFER_COUNT > 1)
} else if (index == 1) {
return (uint8_t *)GFXMMU_VIRTUAL_BUFFER1_BASE_S;
#endif
#else
if (index == 0) {
return physical_frame_buffer_0;
#if (FRAME_BUFFER_COUNT > 1)
} else if (index == 1) {
return physical_frame_buffer_1;
#endif
#endif
} else {
return NULL;
}
}
bool display_get_frame_buffer(display_fb_info_t *fb_dest) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return false;
}
#if PANEL_LTDC_PIXEL_FORMAT == LTDC_PIXEL_FORMAT_ARGB8888
#define FB_PIXEL_SIZE 4
#elif PANEL_LTDC_PIXEL_FORMAT == LTDC_PIXEL_FORMAT_RGB565
#define FB_PIXEL_SIZE 2
#endif
int16_t fb_idx = fb_queue_get_for_write(&drv->queue);
if (fb_idx < 0) {
fb_dest->ptr = NULL;
fb_dest->stride = 0;
return false;
}
uintptr_t addr = (uintptr_t)get_fb_ptr(fb_idx);
uint32_t fb_stride = FRAME_BUFFER_PIXELS_PER_LINE * FB_PIXEL_SIZE;
// We may not utilize whole area of the display
addr += (LCD_HEIGHT - DISPLAY_RESY) / 2 * FB_PIXEL_SIZE;
addr += (LCD_WIDTH - DISPLAY_RESX) / 2 * fb_stride;
display_fb_info_t fb = {
.ptr = (void *)addr,
.stride = fb_stride,
};
mpu_set_active_fb((void *)addr, VIRTUAL_FRAME_BUFFER_SIZE);
memcpy(fb_dest, &fb, sizeof(display_fb_info_t));
return true;
}
void display_refresh(void) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}
int16_t fb_idx = fb_queue_get_for_copy(&drv->queue);
if (fb_idx < 0) {
// No refresh needed as the frame buffer is not in
// the state to be copied to the display
return;
}
if (is_mode_exception()) {
// Disable scheduling of any new background copying
HAL_NVIC_DisableIRQ(LTDC_IRQn);
HAL_NVIC_DisableIRQ(LTDC_ER_IRQn);
display_set_fb((uint32_t)get_fb_ptr(fb_idx));
// Reset the buffer queue so we can eventually continue
// safely in thread mode
fb_queue_reset(&drv->queue);
// Enable normal processing again
HAL_NVIC_EnableIRQ(LTDC_IRQn);
HAL_NVIC_EnableIRQ(LTDC_ER_IRQn);
} else {
// Mark the buffer ready to switch to
fb_queue_set_ready_for_transfer(&drv->queue);
}
}
void display_ensure_refreshed(void) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}
if (!is_mode_exception()) {
bool copy_pending;
// Wait until all frame buffers are written to the display
// so we can be sure there's not scheduled or pending
// background copying
do {
copy_pending = !fb_queue_is_processed(&drv->queue);
__WFI();
} while (copy_pending || drv->update_pending > 0);
}
}
void display_fb_clear(void) {
mpu_set_active_fb(physical_frame_buffer_0, PHYSICAL_FRAME_BUFFER_SIZE);
memset(physical_frame_buffer_0, 0, PHYSICAL_FRAME_BUFFER_SIZE);
mpu_set_active_fb(physical_frame_buffer_1, PHYSICAL_FRAME_BUFFER_SIZE);
memset(physical_frame_buffer_1, 0, PHYSICAL_FRAME_BUFFER_SIZE);
mpu_set_active_fb(NULL, 0);
}
uint32_t display_fb_get_initial_addr(void) {
display_fb_info_t fb_info;
display_get_frame_buffer(&fb_info);
fb_queue_set_ready_for_transfer(&g_display_driver.queue);
fb_queue_get_for_transfer(&g_display_driver.queue);
return (uint32_t)fb_info.ptr;
}
void HAL_LTDC_LineEvenCallback(LTDC_HandleTypeDef *hltdc) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}
if (drv->update_pending > 0) {
drv->update_pending--;
}
int16_t fb_idx = fb_queue_get_for_transfer(&drv->queue);
if (fb_idx >= 0) {
fb_queue_set_switched(&drv->queue);
display_set_fb((uint32_t)get_fb_ptr(fb_idx));
drv->update_pending = 3;
}
HAL_LTDC_ProgramLineEvent(&drv->hlcd_ltdc, LCD_HEIGHT);
}
#endif

View File

@ -0,0 +1,64 @@
#include <trezor_bsp.h>
#include <trezor_rtl.h>
#include <gfx/gfx_bitblt.h>
#include <io/display.h>
#ifdef KERNEL_MODE
void display_copy_rgb565(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgb565_copy_rgb565(&bb_new);
}
void display_fill(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgb565_fill(&bb_new);
}
void display_copy_mono1p(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgb565_copy_mono1p(&bb_new);
}
void display_copy_mono4(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgb565_copy_mono4(&bb_new);
}
#endif

View File

@ -0,0 +1,65 @@
#ifdef KERNEL_MODE
#include <trezor_bsp.h>
#include <trezor_model.h>
#include <gfx/gfx_bitblt.h>
#include <io/display.h>
void display_fill(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_fill(&bb_new);
}
void display_copy_rgb565(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_copy_rgb565(&bb_new);
}
void display_copy_mono1p(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_copy_mono1p(&bb_new);
}
void display_copy_mono4(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_copy_mono4(&bb_new);
}
#endif

View File

@ -0,0 +1,61 @@
#ifdef KERNEL_MODE
#include <trezor_bsp.h>
#include <sys/irq.h>
#include "display_internal.h"
extern uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
extern uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
extern const uint32_t gfxmmu_lut_config[2 * GFXMMU_LUT_SIZE];
void display_gfxmmu_init(display_driver_t *drv) {
__HAL_RCC_GFXMMU_FORCE_RESET();
__HAL_RCC_GFXMMU_RELEASE_RESET();
/* GFXMMU clock enable */
__HAL_RCC_GFXMMU_CLK_ENABLE();
/* Enable GFXMMU interrupt */
NVIC_SetPriority(GFXMMU_IRQn, IRQ_PRI_NORMAL);
NVIC_EnableIRQ(GFXMMU_IRQn);
/* GFXMMU peripheral initialization */
drv->hlcd_gfxmmu.Instance = GFXMMU;
drv->hlcd_gfxmmu.Init.BlocksPerLine = GFXMMU_192BLOCKS;
drv->hlcd_gfxmmu.Init.DefaultValue = 0xFFFFFFFFU;
drv->hlcd_gfxmmu.Init.Buffers.Buf0Address = (uint32_t)physical_frame_buffer_0;
drv->hlcd_gfxmmu.Init.Buffers.Buf1Address = (uint32_t)physical_frame_buffer_1;
drv->hlcd_gfxmmu.Init.Buffers.Buf2Address = 0;
drv->hlcd_gfxmmu.Init.Buffers.Buf3Address = 0;
#if defined(GFXMMU_CR_CE)
drv->hlcd_gfxmmu.Init.CachePrefetch.Activation = DISABLE;
drv->hlcd_gfxmmu.Init.CachePrefetch.CacheLock = GFXMMU_CACHE_LOCK_DISABLE;
drv->hlcd_gfxmmu.Init.CachePrefetch.CacheLockBuffer =
GFXMMU_CACHE_LOCK_BUFFER0; /* NU */
drv->hlcd_gfxmmu.Init.CachePrefetch.CacheForce =
GFXMMU_CACHE_FORCE_ENABLE; /* NU */
drv->hlcd_gfxmmu.Init.CachePrefetch.OutterBufferability =
GFXMMU_OUTTER_BUFFERABILITY_DISABLE;
drv->hlcd_gfxmmu.Init.CachePrefetch.OutterCachability =
GFXMMU_OUTTER_CACHABILITY_DISABLE;
drv->hlcd_gfxmmu.Init.CachePrefetch.Prefetch = GFXMMU_PREFETCH_DISABLE;
#endif /* GFXMMU_CR_CE */
#if defined(GFXMMU_CR_ACE)
drv->hlcd_gfxmmu.Init.AddressCache.Activation = DISABLE;
drv->hlcd_gfxmmu.Init.AddressCache.AddressCacheLockBuffer =
GFXMMU_ADDRESSCACHE_LOCK_BUFFER0;
#endif /* GFXMMU_CR_ACE */
drv->hlcd_gfxmmu.Init.Interrupts.Activation = DISABLE;
drv->hlcd_gfxmmu.Init.Interrupts.UsedInterrupts =
GFXMMU_AHB_MASTER_ERROR_IT; /* NU */
HAL_GFXMMU_Init(&drv->hlcd_gfxmmu);
/* Initialize LUT */
HAL_GFXMMU_ConfigLut(&drv->hlcd_gfxmmu, 0, LCD_HEIGHT,
(uint32_t)&gfxmmu_lut_config);
HAL_GFXMMU_DisableLutLines(&drv->hlcd_gfxmmu, LCD_HEIGHT, 1024 - LCD_HEIGHT);
}
#endif

View File

@ -0,0 +1,83 @@
/*
* 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_bsp.h>
#include <trezor_types.h>
#include "../fb_queue/fb_queue.h"
#ifdef DISPLAY_PANEL_LX200D2406A
#include "panels/lx200d2406a/lx200d2406a.h"
#elif defined DISPLAY_PANEL_STM32U5A9J_DK
#include "panels/stm32u5a9j-dk/stm32u5a9j-dk.h"
#endif
// Hardware requires physical frame buffer alignment
#ifdef USE_TRUSTZONE
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT TZ_SRAM_ALIGNMENT
#else
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT 32
#endif
typedef struct {
bool initialized;
uint16_t update_pending;
frame_buffer_queue_t queue;
// Current display orientation (0, 90, 180, 270)
int orientation_angle;
// Current backlight level ranging from 0 to 255
int backlight_level;
// The current frame buffer selector
DSI_HandleTypeDef hlcd_dsi;
LTDC_HandleTypeDef hlcd_ltdc;
DSI_VidCfgTypeDef DSIVidCfg;
#ifdef DISPLAY_GFXMMU
GFXMMU_HandleTypeDef hlcd_gfxmmu;
#endif
} display_driver_t;
extern display_driver_t g_display_driver;
void display_set_fb(uint32_t fb_addr);
void display_fb_clear(void);
uint32_t display_fb_get_initial_addr(void);
static inline uint32_t is_mode_exception(void) {
uint32_t isr_number = __get_IPSR() & IPSR_ISR_Msk;
// Check if the ISR number is not 0 (thread mode) or 11 (SVCall)
return (isr_number != 0) && (isr_number != 11);
}
void display_ensure_refreshed(void);
void panel_init(display_driver_t *drv);
#ifdef DISPLAY_GFXMMU
void display_gfxmmu_init(display_driver_t *drv);
#endif
#endif // TREZOR_HAL_DISPLAY_INTERNAL_H

View File

@ -0,0 +1,166 @@
#include <trezor_bsp.h>
#include <trezor_rtl.h>
#include <sys/systick.h>
#include "lx200d2406a.h"
#include "../../display_internal.h"
// todo static assert resolution
void panel_init(display_driver_t *drv) {
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x11, 0);
systick_delay_ms(120);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0x36, 0x00);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0x3A, 0x06);
// mipi video mode
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xB0, 0x10);
// Write(Command , 0xB2);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0C);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0C);
// Write(Parameter , 0x00);
// Write(Parameter , 0x00);
// Write(Parameter , 0x00);
// Write(Parameter , 0x33);
// Write(Parameter , 0x00);
// Write(Parameter , 0x33);
HAL_DSI_LongWrite(
&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 10, 0xB2,
(uint8_t[]){0x00, 0x0c, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x33, 0x00, 0x33});
// Write(Command , 0xB7);
// Write(Parameter , 0x00);
// Write(Parameter , 0x06);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xB7,
(uint8_t[]){0x00, 0x06});
// Write(Command , 0xBB);
// Write(Parameter , 0x00);
// Write(Parameter , 0x1E);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xBB,
(uint8_t[]){0x00, 0x1E});
// Write(Command , 0xC0);
// Write(Parameter , 0x00);
// Write(Parameter , 0x2C);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xC0,
(uint8_t[]){0x00, 0x2C});
// Write(Command , 0xC2);
// Write(Parameter , 0x00);
// Write(Parameter , 0x01);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xC2,
(uint8_t[]){0x00, 0x01});
// Write(Command , 0xC3);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0F);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xC3,
(uint8_t[]){0x00, 0x0F});
// Write(Command , 0xC6);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0F);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xC6,
(uint8_t[]){0x00, 0x0F});
// Write(Command , 0xD0);
// Write(Parameter , 0x00);
// Write(Parameter , 0xA7);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xD0,
(uint8_t[]){0x00, 0xA7});
// Write(Command , 0xD0);
// Write(Parameter , 0x00);
// Write(Parameter , 0xA4);
// Write(Parameter , 0x00);
// Write(Parameter , 0xA1);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 4, 0xD0,
(uint8_t[]){0x00, 0xA4, 0x00, 0xA1});
// Write(Command , 0xD6);
// Write(Parameter , 0x00);
// Write(Parameter , 0xA1);
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 2, 0xD6,
(uint8_t[]){0x00, 0xA1});
// Write(Command , 0xE0);
// Write(Parameter , 0x00);
// Write(Parameter , 0xF0);
// Write(Parameter , 0x00);
// Write(Parameter , 0x06);
// Write(Parameter , 0x00);
// Write(Parameter , 0x11);
// Write(Parameter , 0x00);
// Write(Parameter , 0x09);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0A);
// Write(Parameter , 0x00);
// Write(Parameter , 0x28);
// Write(Parameter , 0x00);
// Write(Parameter , 0x37);
// Write(Parameter , 0x00);
// Write(Parameter , 0x44);
// Write(Parameter , 0x00);
// Write(Parameter , 0x4E);
// Write(Parameter , 0x00);
// Write(Parameter , 0x39);
// Write(Parameter , 0x00);
// Write(Parameter , 0x14);
// Write(Parameter , 0x00);
// Write(Parameter , 0x15);
// Write(Parameter , 0x00);
// Write(Parameter , 0x34);
// Write(Parameter , 0x00);
// Write(Parameter , 0x3A);
// HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 28, 0xE0,
// (uint8_t[]){0x00, 0xF0, 0x00, 0x06, 0x00, 0x11, 0x00, 0x09, 0x00, 0x0A,
// 0x00, 0x28, 0x00, 0x37, 0x00, 0x44, 0x00, 0x4E, 0x00, 0x39, 0x00, 0x14,
// 0x00, 0x15, 0x00, 0x34, 0x00, 0x3A});
// Write(Command , 0xE1);
// Write(Parameter , 0x00);
// Write(Parameter , 0xF0);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0E);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0F);
// Write(Parameter , 0x00);
// Write(Parameter , 0x0A);
// Write(Parameter , 0x00);
// Write(Parameter , 0x08);
// Write(Parameter , 0x00);
// Write(Parameter , 0x04);
// Write(Parameter , 0x00);
// Write(Parameter , 0x37);
// Write(Parameter , 0x00);
// Write(Parameter , 0x43);
// Write(Parameter , 0x00);
// Write(Parameter , 0x4D);
// Write(Parameter , 0x00);
// Write(Parameter , 0x35);
// Write(Parameter , 0x00);
// Write(Parameter , 0x12);
// Write(Parameter , 0x00);
// Write(Parameter , 0x13);
// Write(Parameter , 0x00);
// Write(Parameter , 0x32);
// Write(Parameter , 0x00);
// Write(Parameter , 0x39);
// HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 28, 0xE1,
// (uint8_t[]){0x00, 0xF0, 0x00, 0x0E, 0x00, 0x0F, 0x00, 0x0A, 0x00, 0x08,
// 0x00, 0x04, 0x00, 0x37, 0x00, 0x43, 0x00, 0x4D, 0x00, 0x35, 0x00, 0x12,
// 0x00, 0x13, 0x00, 0x32, 0x00, 0x39});
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x21, 0);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x29, 0);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x2C, 0);
}

View File

@ -0,0 +1,49 @@
/*
* This file is part of the Trezor project, https://trezor.io/
*
* Copyright (c) SatoshiLabs
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <trezor_types.h>
#define VSYNC 4
#define VBP 4
#define VFP 660
#define VACT 320
#define HSYNC 30
#define HBP 60
#define HFP 60
#define HACT 240
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_Y_OFFSET 0
#define PANEL_DSI_MODE DSI_VID_MODE_NB_PULSES
#define PANEL_DSI_LANES DSI_ONE_DATA_LANE
#define PANEL_LTDC_PIXEL_FORMAT LTDC_PIXEL_FORMAT_RGB565
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual frame buffer
// due to used GFXMMU settings
#define PHYSICAL_FRAME_BUFFER_SIZE (240 * 320 * 2)
#define VIRTUAL_FRAME_BUFFER_SIZE PHYSICAL_FRAME_BUFFER_SIZE
// Pitch (in pixels) of the virtual frame buffer
#define FRAME_BUFFER_PIXELS_PER_LINE 240

View File

@ -1,35 +1,9 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : gfxmmu_lut.h
* Description : header file for GFX MMU Configuration Table
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __gfxmmu_lut_H
#define __gfxmmu_lut_H
#ifdef __cplusplus
extern "C" {
#endif
// GFX MMU Configuration Table
#ifdef KERNEL_MODE
#include <trezor_rtl.h>
#define GFXMMU_FB_SIZE 733936
#define GFXMMU_LUT_FIRST 0
#define GFXMMU_LUT_LAST 479
#define GFXMMU_LUT_SIZE 480
#include "../../display_internal.h"
static const uint32_t gfxmmu_lut_config[2 * GFXMMU_LUT_SIZE] = {
const uint32_t gfxmmu_lut_config[2 * GFXMMU_LUT_SIZE] = {
0x00413601, // GFXMMU_LUT0L
0x003FFCA0, // GFXMMU_LUT0H
0x00433401, // GFXMMU_LUT1L
@ -992,15 +966,116 @@ static const uint32_t gfxmmu_lut_config[2 * GFXMMU_LUT_SIZE] = {
0x000B2ED0 // GFXMMU_LUT479H
};
#ifdef __cplusplus
void panel_init(display_driver_t* drv) {
/* CMD Mode */
uint8_t InitParam1[3] = {0xFF, 0x83, 0x79};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB9,
InitParam1);
/* SETPOWER */
uint8_t InitParam2[16] = {0x44, 0x1C, 0x1C, 0x37, 0x57, 0x90, 0xD0, 0xE2,
0x58, 0x80, 0x38, 0x38, 0xF8, 0x33, 0x34, 0x42};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 16, 0xB1,
InitParam2);
/* SETDISP */
uint8_t InitParam3[9] = {0x80, 0x14, 0x0C, 0x30, 0x20,
0x50, 0x11, 0x42, 0x1D};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 9, 0xB2,
InitParam3);
/* Set display cycle timing */
uint8_t InitParam4[10] = {0x01, 0xAA, 0x01, 0xAF, 0x01,
0xAF, 0x10, 0xEA, 0x1C, 0xEA};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 10, 0xB4,
InitParam4);
/* SETVCOM */
uint8_t InitParam5[4] = {00, 00, 00, 0xC0};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 4, 0xC7,
InitParam5);
/* Set Panel Related Registers */
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xCC, 0x02);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xD2, 0x77);
uint8_t InitParam6[37] = {0x00, 0x07, 0x00, 0x00, 0x00, 0x08, 0x08, 0x32,
0x10, 0x01, 0x00, 0x01, 0x03, 0x72, 0x03, 0x72,
0x00, 0x08, 0x00, 0x08, 0x33, 0x33, 0x05, 0x05,
0x37, 0x05, 0x05, 0x37, 0x0A, 0x00, 0x00, 0x00,
0x0A, 0x00, 0x01, 0x00, 0x0E};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 37, 0xD3,
InitParam6);
uint8_t InitParam7[34] = {
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
0x18, 0x18, 0x19, 0x19, 0x01, 0x00, 0x03, 0x02, 0x05, 0x04, 0x07, 0x06,
0x23, 0x22, 0x21, 0x20, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 34, 0xD5,
InitParam7);
uint8_t InitParam8[32] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x19, 0x19, 0x18, 0x18, 0x19, 0x19, 0x18, 0x18,
0x06, 0x07, 0x04, 0x05, 0x02, 0x03, 0x00, 0x01,
0x20, 0x21, 0x22, 0x23, 0x18, 0x18, 0x18, 0x18};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 35, 0xD6,
InitParam8);
/* SET GAMMA */
uint8_t InitParam9[42] = {
0x00, 0x16, 0x1B, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0D, 0x0F,
0x18, 0x0E, 0x11, 0x12, 0x11, 0x14, 0x07, 0x12, 0x13, 0x18, 0x00,
0x17, 0x1C, 0x30, 0x36, 0x3F, 0x24, 0x40, 0x09, 0x0C, 0x0F, 0x18,
0x0E, 0x11, 0x14, 0x11, 0x12, 0x07, 0x12, 0x14, 0x18};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xE0,
InitParam9);
uint8_t InitParam10[3] = {0x2C, 0x2C, 00};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 3, 0xB6,
InitParam10);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x00);
uint8_t InitParam11[] = {0x01, 0x00, 0x07, 0x0F, 0x16, 0x1F, 0x27, 0x30, 0x38,
0x40, 0x47, 0x4E, 0x56, 0x5D, 0x65, 0x6D, 0x74, 0x7D,
0x84, 0x8A, 0x90, 0x99, 0xA1, 0xA9, 0xB0, 0xB6, 0xBD,
0xC4, 0xCD, 0xD4, 0xDD, 0xE5, 0xEC, 0xF3, 0x36, 0x07,
0x1C, 0xC0, 0x1B, 0x01, 0xF1, 0x34, 0x00};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1,
InitParam11);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x01);
uint8_t InitParam12[] = {0x00, 0x08, 0x0F, 0x16, 0x1F, 0x28, 0x31, 0x39, 0x41,
0x48, 0x51, 0x59, 0x60, 0x68, 0x70, 0x78, 0x7F, 0x87,
0x8D, 0x94, 0x9C, 0xA3, 0xAB, 0xB3, 0xB9, 0xC1, 0xC8,
0xD0, 0xD8, 0xE0, 0xE8, 0xEE, 0xF5, 0x3B, 0x1A, 0xB6,
0xA0, 0x07, 0x45, 0xC5, 0x37, 0x00};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1,
InitParam12);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x02);
uint8_t InitParam13[42] = {
0x00, 0x09, 0x0F, 0x18, 0x21, 0x2A, 0x34, 0x3C, 0x45, 0x4C, 0x56,
0x5E, 0x66, 0x6E, 0x76, 0x7E, 0x87, 0x8E, 0x95, 0x9D, 0xA6, 0xAF,
0xB7, 0xBD, 0xC5, 0xCE, 0xD5, 0xDF, 0xE7, 0xEE, 0xF4, 0xFA, 0xFF,
0x0C, 0x31, 0x83, 0x3C, 0x5B, 0x56, 0x1E, 0x5A, 0xFF};
HAL_DSI_LongWrite(&drv->hlcd_dsi, 0, DSI_DCS_LONG_PKT_WRITE, 42, 0xC1,
InitParam13);
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, 0xBD, 0x00);
/* Exit Sleep Mode*/
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P0, 0x11, 0x00);
HAL_Delay(120);
/* Display On */
HAL_DSI_ShortWrite(&drv->hlcd_dsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1,
DSI_SET_DISPLAY_ON, 0x00);
HAL_Delay(120);
}
#endif
#endif /*__ gfxmmu_lut_H */
/**
* @}
*/
/**
* @}
*/

View File

@ -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/>.
*/
#pragma once
#define VSYNC 1
#define VBP 12
#define VFP 50
#define VACT 481
#define HSYNC 2
#define HBP 1
#define HFP 1
#define HACT 480
#define LCD_WIDTH 480
#define LCD_HEIGHT 480
#define LCD_Y_OFFSET 1
#define GFXMMU_FB_SIZE 733936
#define GFXMMU_LUT_FIRST 0
#define GFXMMU_LUT_LAST 479
#define GFXMMU_LUT_SIZE 480
#define PANEL_DSI_MODE DSI_VID_MODE_BURST
#define PANEL_DSI_LANES DSI_TWO_DATA_LANES
#define PANEL_LTDC_PIXEL_FORMAT LTDC_PIXEL_FORMAT_ARGB8888
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual frame buffer
// due to used GFXMMU settings
#define PHYSICAL_FRAME_BUFFER_SIZE (184320 * 4)
// Pitch (in pixels) of the virtual frame buffer
#define FRAME_BUFFER_PIXELS_PER_LINE 768
// Size of the virtual frame buffer in bytes
#define VIRTUAL_FRAME_BUFFER_SIZE \
(FRAME_BUFFER_PIXELS_PER_LINE * LCD_HEIGHT * 4)

View File

@ -120,13 +120,7 @@ void display_physical_fb_clear(void) {
static void bg_copy_callback(void) {
display_driver_t *drv = &g_display_driver;
if (drv->queue.rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state and we should never get here
return;
}
drv->queue.entry[drv->queue.rix] = FB_STATE_EMPTY;
drv->queue.rix = (drv->queue.rix + 1) % FRAME_BUFFER_COUNT;
fb_queue_set_done(&drv->queue);
}
// Interrupt routing handling TE signal
@ -135,37 +129,13 @@ static void display_te_interrupt_handler(void) {
__HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
if (drv->queue.rix >= FRAME_BUFFER_COUNT) {
// This is an invalid state and we should never get here
return;
}
int16_t fb_idx = fb_queue_get_for_transfer(&drv->queue);
switch (drv->queue.entry[drv->queue.rix]) {
case FB_STATE_EMPTY:
case FB_STATE_PREPARING:
// No new frame queued
break;
case FB_STATE_COPYING:
// Currently we are copying a data to the display.
// We need to wait for the next TE interrupt.
break;
case FB_STATE_READY:
// Now it's proper time to copy the data to the display
drv->queue.entry[drv->queue.rix] = FB_STATE_COPYING;
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
bg_copy_start_const_out_8(get_fb_ptr(drv->queue.rix),
(uint8_t *)DISPLAY_DATA_ADDRESS,
PHYSICAL_FRAME_BUFFER_SIZE, bg_copy_callback);
// NOTE: when copying is done, this queue slot is marked empty
// (see bg_copy_callback())
break;
default:
// This is an invalid state and we should never get here
break;
if (fb_idx >= 0) {
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
bg_copy_start_const_out_8(get_fb_ptr(fb_idx),
(uint8_t *)DISPLAY_DATA_ADDRESS,
PHYSICAL_FRAME_BUFFER_SIZE, bg_copy_callback);
}
}
@ -187,17 +157,9 @@ bool display_get_frame_buffer(display_fb_info_t *fb) {
return false;
}
frame_buffer_state_t state;
uint8_t fb_idx = fb_queue_get_for_write(&drv->queue);
// We have to wait if the buffer was passed for copying
// to the interrupt handler
do {
state = drv->queue.entry[drv->queue.wix];
} while (state == FB_STATE_READY || state == FB_STATE_COPYING);
drv->queue.entry[drv->queue.wix] = FB_STATE_PREPARING;
fb->ptr = get_fb_ptr(drv->queue.wix);
fb->ptr = get_fb_ptr(fb_idx);
fb->stride = DISPLAY_RESX * sizeof(uint16_t);
// Enable access to the frame buffer from the unprivileged code
mpu_set_active_fb(fb->ptr, PHYSICAL_FRAME_BUFFER_SIZE);
@ -236,7 +198,9 @@ void display_refresh(void) {
return;
}
if (drv->queue.entry[drv->queue.wix] != FB_STATE_PREPARING) {
int16_t fb_idx = fb_queue_get_for_copy(&drv->queue);
if (fb_idx < 0) {
// No refresh needed as the frame buffer is not in
// the state to be copied to the display
return;
@ -255,26 +219,26 @@ void display_refresh(void) {
// Stop any background copying even if it is not finished yet
bg_copy_abort();
// Copy the frame buffer to the display manually
copy_fb_to_display(drv->queue.wix);
copy_fb_to_display(fb_idx);
// Reset the buffer queue so we can eventually continue
// safely in thread mode
drv->queue.wix = 0;
drv->queue.rix = 0;
for (int i = 0; i < FRAME_BUFFER_COUNT; i++) {
drv->queue.entry[i] = FB_STATE_EMPTY;
}
fb_queue_reset(&drv->queue);
// Enable normal processing again
NVIC_EnableIRQ(DISPLAY_TE_INTERRUPT_NUM);
} else {
// Mark the buffer ready to switch to
drv->queue.entry[drv->queue.wix] = FB_STATE_READY;
drv->queue.wix = (drv->queue.wix + 1) % FRAME_BUFFER_COUNT;
fb_queue_set_ready_for_transfer(&drv->queue);
}
#else // BOARDLOADER
wait_for_te_signal();
copy_fb_to_display(drv->queue.wix);
drv->queue.entry[drv->queue.wix] = FB_STATE_EMPTY;
fb_queue_set_ready_for_transfer(&drv->queue);
fb_idx = fb_queue_get_for_transfer(&drv->queue);
if (fb_idx >= 0) {
copy_fb_to_display(fb_idx);
fb_queue_set_done(&drv->queue);
}
#endif
}
@ -293,14 +257,7 @@ void display_ensure_refreshed(void) {
// so we can be sure there's not scheduled or pending
// background copying
do {
copy_pending = false;
for (int i = 0; i < FRAME_BUFFER_COUNT; i++) {
frame_buffer_state_t state = drv->queue.entry[i];
if (state == FB_STATE_READY || state == FB_STATE_COPYING) {
copy_pending = true;
break;
}
}
copy_pending = !fb_queue_is_processed(&drv->queue);
__WFI();
} while (copy_pending);

View File

@ -6,37 +6,7 @@
#ifdef FRAMEBUFFER
// Number of frame buffers used (1 or 2)
// If 1 buffer is selected, some animations may not
// be so smooth but the memory usage is lower.
#define FRAME_BUFFER_COUNT 2
// Each frame buffer can be in one of the following states:
typedef enum {
// The frame buffer is empty and can be written to
FB_STATE_EMPTY = 0,
// The frame buffer pass passed to application
FB_STATE_PREPARING = 1,
// The frame buffer was written to and is ready
// to be copied to the display
FB_STATE_READY = 2,
// The frame buffer is currently being copied to
// the display
FB_STATE_COPYING = 3,
} frame_buffer_state_t;
typedef struct {
// Queue entries
volatile frame_buffer_state_t entry[FRAME_BUFFER_COUNT];
// Read index
// (accessed & updated in the context of the interrupt handlers
uint8_t rix;
// Write index
// (accessed & updated in context of the main thread)
uint8_t wix;
} frame_buffer_queue_t;
#include "../fb_queue/fb_queue.h"
#endif // FRAMEBUFFER

View File

@ -1,93 +0,0 @@
#include <sys/systick.h>
#ifdef KERNEL_MODE
#include <trezor_bsp.h>
#include <trezor_model.h>
#include <trezor_rtl.h>
#include <io/display.h>
#include <sys/mpu.h>
#include <sys/trustzone.h>
#include "../backlight/backlight_pwm.h"
// Hardware requires physical frame buffer alignment
#ifdef USE_TRUSTZONE
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT TZ_SRAM_ALIGNMENT
#else
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT 32
#endif
// Size of the physical frame buffer in bytes
#define PHYSICAL_FRAME_BUFFER_SIZE \
ALIGN_UP_CONST(DISPLAY_RESX *DISPLAY_RESY * 2, \
PHYSICAL_FRAME_BUFFER_ALIGNMENT)
static
__attribute__((section(".fb1"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
#if (FRAME_BUFFER_COUNT > 1)
static
__attribute__((section(".fb2"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
#endif
void display_init(display_content_mode_t mode) {
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStructure;
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_2;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.Pin = GPIO_PIN_0;
// default to keeping display in reset
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
hal_delay(100);
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET);
backlight_pwm_init(mode);
}
void display_deinit(display_content_mode_t mode) { backlight_pwm_deinit(mode); }
void display_set_unpriv_access(bool unpriv) {}
int display_set_backlight(int level) {
return 0;
// return backlight_pwm_set(level);
}
int display_get_backlight(void) { return backlight_pwm_get(); }
int display_set_orientation(int angle) { return angle; }
int display_get_orientation(void) { return 0; }
// Returns the pointer to the physical frame buffer (0.. FRAME_BUFFER_COUNT-1)
// Returns NULL if the framebuffer index is out of range.
static uint8_t *get_fb_ptr(uint32_t index) { return physical_frame_buffer_0; }
bool display_get_frame_buffer(display_fb_info_t *fb) {
fb->ptr = get_fb_ptr(0);
fb->stride = DISPLAY_RESX * sizeof(uint16_t);
// Enable access to the frame buffer from the unprivileged code
mpu_set_active_fb(fb->ptr, PHYSICAL_FRAME_BUFFER_SIZE);
return true;
}
void display_refresh(void) {}
void display_fill(const gfx_bitblt_t *bb) {}
void display_copy_rgb565(const gfx_bitblt_t *bb) {}
void display_copy_mono4(const gfx_bitblt_t *bb) {}
void display_copy_mono1p(const gfx_bitblt_t *bb) {}
#endif

View File

@ -1,226 +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 <trezor_bsp.h>
#include <trezor_model.h>
#include <trezor_rtl.h>
#include <io/display.h>
#include <sys/mpu.h>
#include "display_internal.h"
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240)
#error "Incompatible display resolution"
#endif
#ifdef KERNEL_MODE
// Display driver instance
display_driver_t g_display_driver = {
.initialized = false,
};
void display_init(display_content_mode_t mode) {
display_driver_t *drv = &g_display_driver;
if (drv->initialized) {
return;
}
if (mode == DISPLAY_RESET_CONTENT) {
__HAL_RCC_DSI_FORCE_RESET();
__HAL_RCC_LTDC_FORCE_RESET();
__HAL_RCC_GFXMMU_FORCE_RESET();
__HAL_RCC_DSI_RELEASE_RESET();
__HAL_RCC_LTDC_RELEASE_RESET();
__HAL_RCC_GFXMMU_RELEASE_RESET();
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
mpu_set_active_fb(physical_frame_buffer_0, PHYSICAL_FRAME_BUFFER_SIZE);
memset(physical_frame_buffer_0, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
mpu_set_active_fb(physical_frame_buffer_1, PHYSICAL_FRAME_BUFFER_SIZE);
memset(physical_frame_buffer_1, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
mpu_set_active_fb(NULL, 0);
BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT);
BSP_LCD_SetBrightness(0, 100);
BSP_LCD_DisplayOn(0);
} else {
// Retain display content
BSP_LCD_Reinit(0);
if (drv->current_frame_buffer == 0) {
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
} else {
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
}
}
drv->initialized = true;
}
void display_deinit(display_content_mode_t mode) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
if (mode == DISPLAY_RESET_CONTENT) {
__HAL_RCC_DSI_FORCE_RESET();
__HAL_RCC_LTDC_FORCE_RESET();
__HAL_RCC_GFXMMU_FORCE_RESET();
__HAL_RCC_DSI_RELEASE_RESET();
__HAL_RCC_LTDC_RELEASE_RESET();
__HAL_RCC_GFXMMU_RELEASE_RESET();
}
return;
}
if (mode == DISPLAY_RESET_CONTENT) {
BSP_LCD_DisplayOff(0);
BSP_LCD_SetBrightness(0, 0);
BSP_LCD_DeInit(0);
}
mpu_set_active_fb(NULL, 0);
drv->initialized = false;
}
int display_set_backlight(int level) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return 0;
}
// Just emulation, not doing anything
drv->backlight_level = level;
return level;
}
int display_get_backlight(void) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return 0;
}
return drv->orientation_angle;
}
int display_set_orientation(int angle) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return 0;
}
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;
if (!drv->initialized) {
return 0;
}
return drv->orientation_angle;
}
void display_fill(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_fill(&bb_new);
}
void display_copy_rgb565(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_copy_rgb565(&bb_new);
}
void display_copy_mono1p(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_copy_mono1p(&bb_new);
}
void display_copy_mono4(const gfx_bitblt_t *bb) {
display_fb_info_t fb;
if (!display_get_frame_buffer(&fb)) {
return;
}
gfx_bitblt_t bb_new = *bb;
bb_new.dst_row = (uint8_t *)fb.ptr + (fb.stride * bb_new.dst_y);
bb_new.dst_stride = fb.stride;
gfx_rgba8888_copy_mono4(&bb_new);
}
#endif

View File

@ -1,124 +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 <trezor_bsp.h>
#include <trezor_model.h>
#include <trezor_rtl.h>
#include <io/display.h>
#include <sys/mpu.h>
#include "display_internal.h"
#ifdef USE_TRUSTZONE
#include <sys/trustzone.h>
#endif
#ifdef KERNEL_MODE
// Physical frame buffers in internal SRAM memory
__attribute__((section(".fb1"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
__attribute__((section(".fb2"), aligned(PHYSICAL_FRAME_BUFFER_ALIGNMENT)))
uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
#ifdef USE_TRUSTZONE
void display_set_unpriv_access(bool unpriv) {
// To allow unprivileged access both GFXMMU virtual buffers area and
// underlying SRAM region must be configured as unprivileged.
// Order of GFXMMU and SRAM unprivileged access configuration is important
// to avoid the situation the virtual frame buffer has lower privileges
// than underlying frame buffer in physical memory so LTDC could not
// refresh the display properly.
if (!unpriv) {
tz_set_gfxmmu_unpriv(unpriv);
}
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_0,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
tz_set_sram_unpriv((uint32_t)physical_frame_buffer_1,
PHYSICAL_FRAME_BUFFER_SIZE, unpriv);
if (unpriv) {
tz_set_gfxmmu_unpriv(unpriv);
}
#ifdef USE_DMA2D
tz_set_dma2d_unpriv(unpriv);
#endif
}
#endif // USE_TRUSTZONE
bool display_get_frame_buffer(display_fb_info_t *fb) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
fb->ptr = NULL;
fb->stride = 0;
return false;
}
uintptr_t addr;
if (drv->current_frame_buffer == 0) {
addr = GFXMMU_VIRTUAL_BUFFER1_BASE_S;
} else {
addr = GFXMMU_VIRTUAL_BUFFER0_BASE_S;
}
uint32_t fb_stride = FRAME_BUFFER_PIXELS_PER_LINE * sizeof(uint32_t);
// We do not utilize whole area of the display
// (discovery kit display is 480x480 and we need just 240x240)
addr += (480 - DISPLAY_RESY) / 2 * sizeof(uint32_t);
addr += (480 - DISPLAY_RESX) / 2 * fb_stride;
fb->ptr = (void *)addr;
fb->stride = fb_stride;
// Enable access to the frame buffer from the unprivileged code
mpu_set_active_fb(fb->ptr, VIRTUAL_FRAME_BUFFER_SIZE);
return true;
}
void display_refresh(void) {
display_driver_t *drv = &g_display_driver;
if (!drv->initialized) {
return;
}
// Disable access to the frame buffer from the unprivileged code
mpu_set_active_fb(NULL, 0);
if (drv->current_frame_buffer == 0) {
drv->current_frame_buffer = 1;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
} else {
drv->current_frame_buffer = 0;
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
}
}
#endif

View File

@ -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 TREZOR_HAL_DISPLAY_INTERNAL_H
#define TREZOR_HAL_DISPLAY_INTERNAL_H
#include <trezor_types.h>
#include <rtl/sizedefs.h>
#ifdef USE_TRUSTZONE
#include <sys/trustzone.h>
#endif
// Display driver context.
typedef struct {
// Set if the driver is initialized
bool initialized;
// Current display orientation (0, 90, 180, 270)
int orientation_angle;
// Current backlight level ranging from 0 to 255
int backlight_level;
// The current frame buffer selector
uint32_t current_frame_buffer;
} display_driver_t;
// Display driver instance
extern display_driver_t g_display_driver;
// Hardware requires physical frame buffer alignment
#ifdef USE_TRUSTZONE
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT TZ_SRAM_ALIGNMENT
#else
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT 32
#endif
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual frame buffer
// due to used GFXMMU settings
#define PHYSICAL_FRAME_BUFFER_SIZE \
ALIGN_UP_CONST(184320 * 4, PHYSICAL_FRAME_BUFFER_ALIGNMENT)
// Pitch (in pixels) of the virtual frame buffer
#define FRAME_BUFFER_PIXELS_PER_LINE 768
// Size of the virtual frame buffer in bytes
#define VIRTUAL_FRAME_BUFFER_SIZE \
(FRAME_BUFFER_PIXELS_PER_LINE * DISPLAY_RESY * 4)
// Physical frame buffers in internal SRAM memory
//
// Both frame buffers layers 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];
// 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_DeInit(uint32_t Instance);
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_DisplayOff(uint32_t Instance);
int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr);
#endif // TREZOR_HAL_DISPLAY_INTERNAL_H

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,14 @@
#define VDD_1V8 1
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888
#define DISPLAY_PANEL_STM32U5A9J_DK
#define DISPLAY_GFXMMU 1
#define DISPLAY_RESET_PIN GPIO_PIN_5
#define DISPLAY_RESET_PORT GPIOD
#define DISPLAY_RESET_CLK_ENA __HAL_RCC_GPIOD_CLK_ENABLE
#define DISPLAY_BACKLIGHT_PIN GPIO_PIN_6
#define DISPLAY_BACKLIGHT_PORT GPIOI
#define DISPLAY_BACKLIGHT_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define I2C_COUNT 1
#define I2C_INSTANCE_0 I2C5

View File

@ -9,6 +9,13 @@
#define BTN_POWER_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE
#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565
#define DISPLAY_PANEL_LX200D2406A
#define DISPLAY_RESET_PIN GPIO_PIN_2
#define DISPLAY_RESET_PORT GPIOE
#define DISPLAY_RESET_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE
#define DISPLAY_PWREN_PIN GPIO_PIN_0
#define DISPLAY_PWREN_PORT GPIOE
#define DISPLAY_PWREN_CLK_ENA __HAL_RCC_GPIOE_CLK_ENABLE
#define BACKLIGHT_PWM_FREQ 1000
#define BACKLIGHT_PWM_TIM TIM17

View File

@ -410,6 +410,9 @@ STATIC mp_obj_tuple_t mod_trezorutils_version_obj = {
/// """UI layout identifier ("tt" for model T, "tr" for models One and R)."""
/// USE_THP: bool
/// """Whether the firmware supports Trezor-Host Protocol (version 2)."""
/// if __debug__:
/// DISABLE_ANIMATION: bool
/// """Whether the firmware should disable animations."""
STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorutils)},
@ -502,6 +505,13 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
#else
#error Unknown layout
#endif
#if !PYOPT
#if DISABLE_ANIMATION
{MP_ROM_QSTR(MP_QSTR_DISABLE_ANIMATION), mp_const_true},
#else
{MP_ROM_QSTR(MP_QSTR_DISABLE_ANIMATION), mp_const_false},
#endif // TREZOR_DISABLE_ANIMATION
#endif // PYOPT
};
STATIC MP_DEFINE_CONST_DICT(mp_module_trezorutils_globals,

View File

@ -152,3 +152,6 @@ UI_LAYOUT: str
"""UI layout identifier ("tt" for model T, "tr" for models One and R)."""
USE_THP: bool
"""Whether the firmware supports Trezor-Host Protocol (version 2)."""
if __debug__:
DISABLE_ANIMATION: bool
"""Whether the firmware should disable animations."""

View File

@ -39,9 +39,12 @@ def configure(
]
sources += [
"embed/io/display/stm32u5a9j-dk/display_driver.c",
"embed/io/display/stm32u5a9j-dk/display_fb.c",
"embed/io/display/stm32u5a9j-dk/display_ltdc_dsi.c",
"embed/io/display/ltdc_dsi/display_driver.c",
"embed/io/display/ltdc_dsi/panels/stm32u5a9j-dk/stm32u5a9j-dk.c",
"embed/io/display/ltdc_dsi/display_fb.c",
"embed/io/display/ltdc_dsi/display_fb_rgb888.c",
"embed/io/display/ltdc_dsi/display_gfxmmu.c",
"embed/io/display/fb_queue/fb_queue.c",
]
paths += ["embed/io/display/inc"]

View File

@ -47,6 +47,7 @@ def configure(
sources += ["embed/io/display/st-7789/display_io.c"]
sources += ["embed/io/display/st-7789/display_panel.c"]
sources += ["embed/io/display/st-7789/panels/lx154a2482.c"]
sources += ["embed/io/display/fb_queue/fb_queue.c"]
paths += ["embed/io/display/inc"]
sources += ["embed/io/display/backlight/stm32/backlight_pwm.c"]

View File

@ -39,7 +39,11 @@ def configure(
]
sources += [
"embed/io/display/st7785ma/display_driver.c",
"embed/io/display/ltdc_dsi/display_driver.c",
"embed/io/display/ltdc_dsi/panels/lx200d2406a/lx200d2406a.c",
"embed/io/display/ltdc_dsi/display_fb.c",
"embed/io/display/ltdc_dsi/display_fb_rgb565.c",
"embed/io/display/fb_queue/fb_queue.c",
"embed/io/display/backlight/stm32/backlight_pwm.c",
]

View File

@ -24,7 +24,7 @@ else:
if __debug__:
trezorui2.disable_animation(bool(utils.DISABLE_ANIMATION))
trezorui2.disable_animation(utils.DISABLE_ANIMATION)
# all rendering is done through a singleton of `Display`

View File

@ -33,17 +33,20 @@ from trezorutils import ( # noqa: F401
)
from typing import TYPE_CHECKING
DISABLE_ANIMATION = 0
if __debug__:
if EMULATOR:
import uos
DISABLE_ANIMATION = int(uos.getenv("TREZOR_DISABLE_ANIMATION") or "0")
LOG_MEMORY = int(uos.getenv("TREZOR_LOG_MEMORY") or "0")
DISABLE_ANIMATION = uos.getenv("TREZOR_DISABLE_ANIMATION") == "1"
LOG_MEMORY = uos.getenv("TREZOR_LOG_MEMORY") == "1"
else:
from trezorutils import DISABLE_ANIMATION # noqa: F401
LOG_MEMORY = 0
else:
DISABLE_ANIMATION = False
if TYPE_CHECKING:
from typing import Any, Iterator, Protocol, Sequence, TypeVar

View File

@ -284,11 +284,15 @@ void norcow_wipe(void) {
// Erase the active sector first, because it contains sensitive data.
erase_sector(norcow_active_sector, sectrue);
#if STORAGE_INSECURE_TESTING_MODE && !PRODUCTION
// skip erasing inactive sectors
#else
for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) {
if (i != norcow_active_sector) {
erase_sector(i, secfalse);
}
}
#endif
norcow_active_version = NORCOW_VERSION;
norcow_write_sector = norcow_active_sector;
norcow_free_offset = NORCOW_STORAGE_START;

View File

@ -86,8 +86,12 @@ const uint32_t V0_PIN_EMPTY = 1;
// up constant storage space.
#define MAX_WIPE_CODE_LEN 50
#if STORAGE_INSECURE_TESTING_MODE && !PRODUCTION
#define PIN_ITER_COUNT 1
#else
// The total number of iterations to use in PBKDF2.
#define PIN_ITER_COUNT 20000
#endif
// The minimum number of milliseconds between progress updates.
#define MIN_PROGRESS_UPDATE_MS 100

View File

@ -2,3 +2,15 @@
#include <stdint.h>
uint32_t hamming_weight(uint32_t value);
#ifndef STORAGE_INSECURE_TESTING_MODE
#define STORAGE_INSECURE_TESTING_MODE 0
#endif
#if STORAGE_INSECURE_TESTING_MODE
#if PRODUCTION
#error "STORAGE_INSECURE_TESTING_MODE can't be used in production"
#else
#pragma message("STORAGE IS INSECURE DO NOT USE THIS IN PRODUCTION")
#endif
#endif