You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/trezorhal/stm32f4/displays/ltdc.c

420 lines
13 KiB

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