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/display/st-7789/display_panel.c

236 lines
7.0 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/>.
*/
// using const volatile instead of #define results in binaries that change
// only in 1-byte when the flag changes.
// using #define leads compiler to over-optimize the code leading to bigger
// differencies in the resulting binaries.
#include "display_panel.h"
#include "display_io.h"
#ifdef TREZOR_MODEL_T
#include "panels/154a.h"
#include "panels/lx154a2411.h"
#include "panels/lx154a2422.h"
#include "panels/tf15411a.h"
#else
#include "panels/lx154a2422.h"
#endif
// using const volatile instead of #define results in binaries that change
// only in 1-byte when the flag changes.
// using #define leads compiler to over-optimize the code leading to bigger
// differencies in the resulting binaries.
const volatile uint8_t DISPLAY_ST7789V_INVERT_COLORS2 = 1;
#ifdef DISPLAY_IDENTIFY
static uint32_t read_display_id(uint8_t command) {
volatile uint8_t c = 0;
uint32_t id = 0;
ISSUE_CMD_BYTE(command);
c = *DISPLAY_DATA_ADDRESS; // first returned value is a dummy value and
// should be discarded
c = *DISPLAY_DATA_ADDRESS;
id |= (c << 16);
c = *DISPLAY_DATA_ADDRESS;
id |= (c << 8);
c = *DISPLAY_DATA_ADDRESS;
id |= c;
return id;
}
uint32_t display_panel_identify(void) {
static uint32_t id = 0x000000U;
static bool id_initialized = false;
// Return immediately if id has been already initialized
if (id_initialized) return id;
// RDDID: Read Display ID
id = read_display_id(0x04);
// the default RDDID for ILI9341 should be 0x8000.
// some display modules return 0x0.
// the ILI9341 has an extra id, let's check it here.
if ((id != DISPLAY_ID_ST7789V) && (id != DISPLAY_ID_GC9307)) {
// Read ID4
uint32_t id4 = read_display_id(0xD3);
if (id4 == DISPLAY_ID_ILI9341V) { // definitely found a ILI9341
id = id4;
}
}
id_initialized = true;
return id;
}
#else
uint32_t display_panbel_identify(void) { return DISPLAY_ID_ST7789V; }
#endif
bool display_panel_is_inverted() {
bool inv_on = false;
uint32_t id = display_panel_identify();
if (id == DISPLAY_ID_ST7789V) {
volatile uint8_t c = 0;
ISSUE_CMD_BYTE(0x09); // read display status
c = *DISPLAY_DATA_ADDRESS; // don't care
c = *DISPLAY_DATA_ADDRESS; // don't care
c = *DISPLAY_DATA_ADDRESS; // don't care
c = *DISPLAY_DATA_ADDRESS;
if (c & 0x20) {
inv_on = true;
}
c = *DISPLAY_DATA_ADDRESS; // don't care
}
return inv_on;
}
void display_panel_sleep(void) {
uint32_t id = display_panel_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
(id == DISPLAY_ID_ST7789V)) {
ISSUE_CMD_BYTE(0x28); // DISPOFF: Display Off
ISSUE_CMD_BYTE(0x10); // SLPIN: Sleep in
HAL_Delay(5); // need to wait 5 milliseconds after "sleep in" before
// sending any new commands
}
}
void display_panel_unsleep(void) {
uint32_t id = display_panel_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
(id == DISPLAY_ID_ST7789V)) {
ISSUE_CMD_BYTE(0x11); // SLPOUT: Sleep Out
HAL_Delay(5); // need to wait 5 milliseconds after "sleep out" before
// sending any new commands
ISSUE_CMD_BYTE(0x29); // DISPON: Display On
}
}
void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
uint16_t y1) {
uint32_t id = display_panel_identify();
if ((id == DISPLAY_ID_ILI9341V) || (id == DISPLAY_ID_GC9307) ||
(id == DISPLAY_ID_ST7789V)) {
ISSUE_CMD_BYTE(0x2A);
ISSUE_DATA_BYTE(x0 >> 8);
ISSUE_DATA_BYTE(x0 & 0xFF);
ISSUE_DATA_BYTE(x1 >> 8);
ISSUE_DATA_BYTE(x1 & 0xFF); // column addr set
ISSUE_CMD_BYTE(0x2B);
ISSUE_DATA_BYTE(y0 >> 8);
ISSUE_DATA_BYTE(y0 & 0xFF);
ISSUE_DATA_BYTE(y1 >> 8);
ISSUE_DATA_BYTE(y1 & 0xFF); // row addr set
ISSUE_CMD_BYTE(0x2C);
}
}
void display_panel_set_little_endian(void) {
uint32_t id = display_panel_identify();
if (id == DISPLAY_ID_GC9307) {
// CANNOT SET ENDIAN FOR GC9307
} else if (id == DISPLAY_ID_ST7789V) {
ISSUE_CMD_BYTE(0xB0);
ISSUE_DATA_BYTE(0x00);
ISSUE_DATA_BYTE(0xF8);
} else if (id == DISPLAY_ID_ILI9341V) {
// Interface Control: XOR BGR as ST7789V does
ISSUE_CMD_BYTE(0xF6);
ISSUE_DATA_BYTE(0x09);
ISSUE_DATA_BYTE(0x30);
ISSUE_DATA_BYTE(0x20);
}
}
void display_panel_set_big_endian(void) {
uint32_t id = display_panel_identify();
if (id == DISPLAY_ID_GC9307) {
// CANNOT SET ENDIAN FOR GC9307
} else if (id == DISPLAY_ID_ST7789V) {
ISSUE_CMD_BYTE(0xB0);
ISSUE_DATA_BYTE(0x00);
ISSUE_DATA_BYTE(0xF0);
} else if (id == DISPLAY_ID_ILI9341V) {
// Interface Control: XOR BGR as ST7789V does
ISSUE_CMD_BYTE(0xF6);
ISSUE_DATA_BYTE(0x09);
ISSUE_DATA_BYTE(0x30);
ISSUE_DATA_BYTE(0x00);
}
}
void display_panal_init(void) {
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); // LCD_RST/PC14
// wait 10 milliseconds. only needs to be low for 10 microseconds.
// my dev display module ties display reset and touch panel reset together.
// keeping this low for max(display_reset_time, ctpm_reset_time) aids
// development and does not hurt.
HAL_Delay(10);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_SET); // LCD_RST/PC14
// max wait time for hardware reset is 120 milliseconds
// (experienced display flakiness using only 5ms wait before sending commands)
HAL_Delay(120);
// identify the controller we will communicate with
#ifdef TREZOR_MODEL_T
uint32_t id = display_panel_identify();
if (id == DISPLAY_ID_GC9307) {
tf15411a_init_seq();
} else if (id == DISPLAY_ID_ST7789V) {
if (DISPLAY_ST7789V_INVERT_COLORS2) {
lx154a2422_init_seq();
} else {
lx154a2411_init_seq();
}
} else if (id == DISPLAY_ID_ILI9341V) {
_154a_init_seq();
}
#else
lx154a2422_init_seq();
#endif
display_panel_unsleep();
}
void display_panel_init_gamma(void) {
#ifdef TREZOR_MODEL_T
uint32_t id = display_panel_identify();
if (id == DISPLAY_ID_ST7789V && display_panel_is_inverted()) {
// newest TT display - set proper gamma
lx154a2422_gamma();
} else if (id == DISPLAY_ID_ST7789V) {
lx154a2411_gamma();
}
#endif
}
void display_panel_rotate(int angle) {
#ifdef TREZOR_MODEL_T
uint32_t id = display_panel_identify();
if (id == DISPLAY_ID_GC9307) {
tf15411a_rotate(angle);
} else {
lx154a2422_rotate(angle);
}
#else
lx154a2422_rotate(angle);
#endif
}