parent
a47ae5da1a
commit
f085c50931
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GL_BITBLT_H
|
||||
#define GL_BITBLT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gl_color.h"
|
||||
|
||||
// These module provides provides low-level bit block transfer (bitblt)
|
||||
// operations on different bitmap/framebuffer types.
|
||||
//
|
||||
// `fill` - fills a rectangle with a solid color (with an optional
|
||||
// alpha, allowing color blending).
|
||||
//
|
||||
// `copy` - copies a bitmap or part of it to the destination bitmap.
|
||||
//
|
||||
// `blend` - blends a bitmap with a 1- or 4-bit alpha channel to the
|
||||
// destination using background and foreground colors.
|
||||
//
|
||||
// These operations might be accelerated using DMA2D (ChromART accelerator)
|
||||
// on the STM32 platform.
|
||||
|
||||
// Represents a set of parameters for a bit block transfer operation.
|
||||
typedef struct {
|
||||
// Pointer to the destination bitmap's first row
|
||||
void* dst_row;
|
||||
// Number of bytes per line in the destination bitmap
|
||||
uint16_t dst_stride;
|
||||
// X-coordinate of the top-left corner inside the destination
|
||||
uint16_t dst_x;
|
||||
// Y-coordinate of the top-left corner inside the destination
|
||||
uint16_t dst_y;
|
||||
// Height of the filled/copied/blended area
|
||||
uint16_t height;
|
||||
// Width of the filled/copied/blended area
|
||||
uint16_t width;
|
||||
|
||||
// Pointer to the source bitmap's first row
|
||||
// (unused for fill operations)
|
||||
void* src_row;
|
||||
// Number of bytes per line in the source bitmap
|
||||
// (unused for fill operations)
|
||||
uint16_t src_stride;
|
||||
// X-coordinate of the origin in the source bitmap
|
||||
// (unused for fill operations)
|
||||
uint16_t src_x;
|
||||
// Y-coordinate of the origin in the source bitmap
|
||||
// (unused for fill operations)
|
||||
uint16_t src_y;
|
||||
|
||||
// Foreground color used when copying/blending/filling
|
||||
gl_color_t src_fg;
|
||||
// Background color used when copying mono bitmaps
|
||||
gl_color_t src_bg;
|
||||
// Alpha value for fill operation (255 => normal fill, 0 => noop)
|
||||
uint8_t src_alpha;
|
||||
|
||||
} gl_bitblt_t;
|
||||
|
||||
// Functions for RGB565 bitmap/framebuffer
|
||||
|
||||
// Fills a rectangle with a solid color
|
||||
void gl_rgb565_fill(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 1-bit alpha channel)
|
||||
void gl_rgb565_copy_mono1p(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 4-bit alpha channel)
|
||||
void gl_rgb565_copy_mono4(const gl_bitblt_t* bb);
|
||||
// Copies an RGB565 bitmap
|
||||
void gl_rgb565_copy_rgb565(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 4-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_rgb565_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
// Functions for RGBA8888 bitmap/framebuffer
|
||||
void gl_rgba8888_fill(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 1-bit alpha channel)
|
||||
void gl_rgba8888_copy_mono1p(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 4-bit alpha channel)
|
||||
void gl_rgba8888_copy_mono4(const gl_bitblt_t* bb);
|
||||
// Copies an RGB565 bitmap
|
||||
void gl_rgba8888_copy_rgb565(const gl_bitblt_t* bb);
|
||||
// Copies an RGBA8888 bitmap
|
||||
void gl_rgba8888_copy_rgba8888(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 4-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_rgba8888_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
// Functions for Mono8 bitmap/framebuffer
|
||||
void gl_mono8_fill(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 1-bit alpha channel)
|
||||
void gl_mono8_copy_mono1p(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 4-bit alpha channel)
|
||||
void gl_mono8_copy_mono4(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 1-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_mono8_blend_mono1p(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 4-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_mono8_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
#endif // GL_BITBLT_H
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 "gl_bitblt.h"
|
||||
|
||||
void gl_mono8_fill(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = fg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_copy_mono1p(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
uint8_t bg = gl_color_lum(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : bg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_copy_mono4(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
uint8_t bg = gl_color_lum(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t src_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t src_lum = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0xF;
|
||||
dst_ptr[x] = (fg * src_lum + bg * (15 - src_lum)) / 15;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_blend_mono1p(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : dst_ptr[x];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_blend_mono4(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t src_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t src_alpha = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0x0F;
|
||||
dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (15 - src_alpha)) / 15;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 "gl_bitblt.h"
|
||||
|
||||
#if USE_DMA2D
|
||||
#include "dma2d_bitblt.h"
|
||||
#endif
|
||||
|
||||
void gl_rgb565_fill(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row)) {
|
||||
dma2d_rgb565_fill(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
if (bb->src_alpha == 255) {
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = bb->src_fg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
} else {
|
||||
uint8_t alpha = bb->src_alpha;
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color16_blend_a8(bb->src_fg, dst_ptr[x], alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_copy_mono1p(const gl_bitblt_t* bb) {
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint16_t fg = gl_color_to_color16(bb->src_fg);
|
||||
uint16_t bg = gl_color_to_color16(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : bg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_copy_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
|
||||
dma2d_rgb565_copy_mono4(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
const gl_color16_t* gradient =
|
||||
gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
|
||||
dst_ptr[x] = gradient[fg_lum];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_copy_rgb565(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
|
||||
dma2d_rgb565_copy_rgb565(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = src_ptr[x];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_blend_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
|
||||
dma2d_rgb565_blend_mono4(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
|
||||
dst_ptr[x] = gl_color16_blend_a4(
|
||||
bb->src_fg, gl_color16_to_color(dst_ptr[x]), fg_alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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 "gl_bitblt.h"
|
||||
|
||||
#if USE_DMA2D
|
||||
#include "dma2d_bitblt.h"
|
||||
#endif
|
||||
|
||||
void gl_rgba8888_fill(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row)) {
|
||||
dma2d_rgba8888_fill(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
if (bb->src_alpha == 255) {
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color_to_color32(bb->src_fg);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
} else {
|
||||
uint8_t alpha = bb->src_alpha;
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color32_blend_a8(
|
||||
bb->src_fg, gl_color32_to_color(dst_ptr[x]), alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_mono1p(const gl_bitblt_t* bb) {
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint32_t fg = gl_color_to_color32(bb->src_fg);
|
||||
uint32_t bg = gl_color_to_color32(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : bg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
|
||||
dma2d_rgba8888_copy_mono4(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
const gl_color32_t* gradient =
|
||||
gl_color32_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
|
||||
dst_ptr[x] = gradient[fg_lum];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_rgb565(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
|
||||
dma2d_rgba8888_copy_rgb565(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color16_to_color32(src_ptr[x]);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_rgba8888(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
|
||||
dma2d_rgba8888_copy_rgba8888(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint32_t* src_ptr = (uint32_t*)bb->src_row + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = src_ptr[x];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_blend_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (dma2d_accessible(bb->dst_row) && dma2d_accessible(bb->src_row)) {
|
||||
dma2d_rgba8888_blend_mono4(bb);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
|
||||
dst_ptr[x] = gl_color32_blend_a4(
|
||||
bb->src_fg, gl_color32_to_color(dst_ptr[x]), fg_alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
@ -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/>.
|
||||
*/
|
||||
|
||||
#include "gl_color.h"
|
||||
#include "colors.h"
|
||||
|
||||
const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg_color,
|
||||
gl_color_t bg_color) {
|
||||
static gl_color16_t cache[16] = {0};
|
||||
|
||||
if (gl_color_to_color16(bg_color) != cache[0] ||
|
||||
gl_color_to_color16(fg_color) != cache[15]) {
|
||||
for (int alpha = 0; alpha < 16; alpha++) {
|
||||
cache[alpha] = gl_color16_blend_a4(fg_color, bg_color, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
return (const gl_color16_t*)&cache[0];
|
||||
}
|
||||
|
||||
const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg_color,
|
||||
gl_color_t bg_color) {
|
||||
static gl_color32_t cache[16] = {0};
|
||||
|
||||
if (bg_color != gl_color32_to_color(cache[0]) ||
|
||||
fg_color != gl_color32_to_color(cache[15])) {
|
||||
for (int alpha = 0; alpha < 16; alpha++) {
|
||||
cache[alpha] = gl_color32_blend_a4(fg_color, bg_color, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
return (const gl_color32_t*)&cache[0];
|
||||
}
|
@ -0,0 +1,308 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GL_COLOR_H
|
||||
#define GL_COLOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define GL_COLOR_16BIT
|
||||
// #define GL_COLOR_32BIT
|
||||
|
||||
// Color in RGB565 format
|
||||
//
|
||||
// |15 8 | 7 0|
|
||||
// |---------------------------------|
|
||||
// |r r r r r g g g | g g g b b b b b|
|
||||
// |---------------------------------|
|
||||
|
||||
typedef uint16_t gl_color16_t;
|
||||
|
||||
// Color in RGBA8888 format
|
||||
//
|
||||
// |31 24 |23 16 |15 8 | 7 0 |
|
||||
// |----------------------------------------------------------------------|
|
||||
// |a a a a a a a a | r r r r r r r r | g g g g g g g g | b b b b b b b b |
|
||||
// |----------------------------------------------------------------------|
|
||||
//
|
||||
|
||||
typedef uint32_t gl_color32_t;
|
||||
|
||||
#ifdef GL_COLOR_16BIT
|
||||
#define gl_color_t gl_color16_t
|
||||
#define gl_color_to_color16(c) (c)
|
||||
#define gl_color16_to_color(c) (c)
|
||||
#define gl_color_to_color32(c) (gl_color16_to_color32(c))
|
||||
#define gl_color32_to_color(c) (gl_color32_to_color16(c))
|
||||
#define gl_color_lum(c) (gl_color16_lum(c))
|
||||
#elif GL_COLOR_32BIT
|
||||
#define gl_color_t gl_color32_t
|
||||
#define gl_color_to_color16(c) (gl_color32_to_color16(c))
|
||||
#define gl_color16_to_color(c) (gl_color16_to_color32(c))
|
||||
#define gl_color_to_color32(c) (c)
|
||||
#define gl_color32_to_color(c) (c)
|
||||
#else
|
||||
#error "GL_COLOR_16BIT/32BIT not specified"
|
||||
#endif
|
||||
|
||||
// Constructs a 16-bit color from the given red (r),
|
||||
// green (g), and blue (b) values in the range 0..255
|
||||
static inline gl_color16_t gl_color16_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return ((r & 0xF8U) << 8) | ((g & 0xFCU) << 3) | ((b & 0xF8U) >> 3);
|
||||
}
|
||||
|
||||
// Constructs a 32-bit color from the given red (r),
|
||||
// green (g), and blue (b) values in the range 0..255.
|
||||
// Alpha is set to 255.
|
||||
static inline gl_color32_t gl_color32_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
|
||||
// Converts a 16-bit color to a 32-bit color; alpha is set to 255
|
||||
static inline gl_color32_t gl_color16_to_color32(gl_color16_t color) {
|
||||
uint32_t r = (color & 0xF800) >> 8;
|
||||
uint32_t g = (color & 0x07E0) >> 3;
|
||||
uint32_t b = (color & 0x001F) << 3;
|
||||
|
||||
r |= (r >> 5);
|
||||
g |= (g >> 6);
|
||||
b |= (b >> 5);
|
||||
|
||||
return (0xFFU << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
// Converts 32-bit color to 16-bit color, alpha is ignored
|
||||
static inline gl_color16_t gl_color32_to_color16(gl_color32_t color) {
|
||||
uint16_t r = (color & 0x00F80000) >> 8;
|
||||
uint16_t g = (color & 0x0000FC00) >> 5;
|
||||
uint16_t b = (color & 0x000000F8) >> 3;
|
||||
|
||||
return r | g | b;
|
||||
}
|
||||
|
||||
// Converts 16-bit color into luminance (ranging from 0 to 255)
|
||||
static inline uint8_t gl_color16_lum(gl_color16_t color) {
|
||||
uint32_t r = (color & 0xF800) >> 8;
|
||||
uint32_t g = (color & 0x07E0) >> 3;
|
||||
uint32_t b = (color & 0x001F) << 3;
|
||||
|
||||
r |= (r >> 5);
|
||||
g |= (g >> 6);
|
||||
b |= (b >> 5);
|
||||
|
||||
return (r + g + b) / 3;
|
||||
}
|
||||
|
||||
#ifdef GL_COLOR_16BIT
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a4(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0xF800) >> 11;
|
||||
uint16_t bg_r = (bg & 0xF800) >> 11;
|
||||
|
||||
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_g = (fg & 0x07E0) >> 5;
|
||||
uint16_t bg_g = (bg & 0x07E0) >> 5;
|
||||
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_b = (fg & 0x001F) >> 0;
|
||||
uint16_t bg_b = (bg & 0x001F) >> 0;
|
||||
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
|
||||
|
||||
return (r << 11) | (g << 5) | b;
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a8(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0xF800) >> 11;
|
||||
uint16_t bg_r = (bg & 0xF800) >> 11;
|
||||
|
||||
uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255;
|
||||
|
||||
uint16_t fg_g = (fg & 0x07E0) >> 5;
|
||||
uint16_t bg_g = (bg & 0x07E0) >> 5;
|
||||
uint16_t g = (fg_g * alpha + (bg_g * (255 - alpha))) / 255;
|
||||
|
||||
uint16_t fg_b = (fg & 0x001F) >> 0;
|
||||
uint16_t bg_b = (bg & 0x001F) >> 0;
|
||||
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
|
||||
|
||||
return (r << 11) | (g << 5) | b;
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 32-bit format
|
||||
//
|
||||
// If alpha is 0, the function returns the background color
|
||||
// If alpha is 15, the function returns the foreground color
|
||||
static inline gl_color32_t gl_color32_blend_a4(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0xF800) >> 8;
|
||||
fg_r |= fg_r >> 5;
|
||||
uint16_t bg_r = (bg & 0xF800) >> 8;
|
||||
bg_r |= bg_r >> 5;
|
||||
|
||||
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_g = (fg & 0x07E0) >> 3;
|
||||
fg_g |= fg_g >> 6;
|
||||
uint16_t bg_g = (bg & 0x07E0) >> 3;
|
||||
bg_g |= bg_g >> 6;
|
||||
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_b = (fg & 0x001F) << 3;
|
||||
fg_b |= fg_b >> 5;
|
||||
uint16_t bg_b = (bg & 0x001F) << 3;
|
||||
bg_b |= bg_b >> 5;
|
||||
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
|
||||
|
||||
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 8-bit alpha
|
||||
//
|
||||
// Returns a color in 32-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 255, the function returns the foreground color
|
||||
static inline gl_color32_t gl_color32_blend_a8(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0xF800) >> 8;
|
||||
fg_r |= fg_r >> 5;
|
||||
uint16_t bg_r = (bg & 0xF800) >> 8;
|
||||
bg_r |= bg_r >> 5;
|
||||
|
||||
uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255;
|
||||
|
||||
uint16_t fg_g = (fg & 0x07E0) >> 3;
|
||||
fg_g |= fg_g >> 6;
|
||||
uint16_t bg_g = (bg & 0x07E0) >> 3;
|
||||
bg_g |= bg_g >> 6;
|
||||
uint16_t g = (fg_g * alpha + (bg_g * (255 - alpha))) / 255;
|
||||
|
||||
uint16_t fg_b = (fg & 0x001F) << 3;
|
||||
fg_b |= fg_b >> 5;
|
||||
uint16_t bg_b = (bg & 0x001F) << 3;
|
||||
bg_b |= bg_b >> 5;
|
||||
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
|
||||
|
||||
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
|
||||
#elif GL_COLOR_32BIT
|
||||
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a4(gl_color32_t fg, gl_color32_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
|
||||
uint16_t bg_r = (bg & 0x00FF0000) >> 16;
|
||||
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_g = (fg & 0x0000FF00) >> 8;
|
||||
uint16_t bg_g = (bg & 0x0000FF00) >> 8;
|
||||
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_b = (fg & 0x000000FF) >> 0;
|
||||
uint16_t bg_b = (bg & 0x000000FF) >> 0;
|
||||
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
|
||||
|
||||
return gl_color16_rgb(r, g, b)
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 8-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 255, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a8(gl_color32_t fg, gl_color32_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
|
||||
uint16_t bg_r = (bg & 0x00FF0000) >> 16;
|
||||
uint16_t r = (fg_r * alpha + (bg_r * (255 - alpha))) / 255;
|
||||
|
||||
uint16_t fg_g = (fg & 0x0000FF00) >> 8;
|
||||
uint16_t bg_g = (bg & 0x0000FF00) >> 8;
|
||||
uint16_t g = (fg_g * alpha + (bg_g * (255 - alpha))) / 255;
|
||||
|
||||
uint16_t fg_b = (fg & 0x000000FF) >> 0;
|
||||
uint16_t bg_b = (bg & 0x000000FF) >> 0;
|
||||
uint16_t b = (fg_b * alpha + (bg_b * (255 - alpha))) / 255;
|
||||
|
||||
return gl_color16_rgb(r, g, b)
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 32-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color32_t gl_color32_blend_a4(gl_color32_t fg, gl_color32_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0x00FF0000) >> 16;
|
||||
uint16_t bg_r = (bg & 0x00FF0000) >> 16;
|
||||
uint16_t r = (fg_r * alpha + (bg_r * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_g = (fg & 0x0000FF00) >> 8;
|
||||
uint16_t bg_g = (bg & 0x0000FF00) >> 8;
|
||||
uint16_t g = (fg_g * alpha + (bg_g * (15 - alpha))) / 15;
|
||||
|
||||
uint16_t fg_b = (fg & 0x000000FF) >> 0;
|
||||
uint16_t bg_b = (bg & 0x000000FF) >> 0;
|
||||
uint16_t b = (fg_b * alpha + (bg_b * (15 - alpha))) / 15;
|
||||
|
||||
return gl_color32_rgb(r, g, b);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "GL_COLOR_16BIT/32BIT not specified"
|
||||
#endif
|
||||
|
||||
// Returns a gradient as an array of 16 consecutive 16-bit colors
|
||||
//
|
||||
// Each element in the array represents a color, with `retval[0]` being
|
||||
// the background (`bg`) color and `retval[15]` the foreground (`fg`) color
|
||||
const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg, gl_color_t bg);
|
||||
|
||||
// Returns a gradient as an array of 16 consecutive 32-bit colors
|
||||
//
|
||||
// Each element in the array represents a color, with `retval[0]` being
|
||||
// the background (`bg`) color and `retval[15]` the foreground (`fg`) color
|
||||
const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg, gl_color_t bg);
|
||||
|
||||
#endif // TREZORHAL_GL_COLOR_H
|
@ -0,0 +1,270 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <display.h>
|
||||
|
||||
#include "display_draw.h"
|
||||
#include "fonts/fonts.h"
|
||||
#include "gl_draw.h"
|
||||
|
||||
typedef struct {
|
||||
int16_t dst_x;
|
||||
int16_t dst_y;
|
||||
int16_t src_x;
|
||||
int16_t src_y;
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
} gl_clip_t;
|
||||
|
||||
static inline gl_clip_t gl_clip(gl_rect_t dst, const gl_bitmap_t* bitmap) {
|
||||
int16_t dst_x = dst.x0;
|
||||
int16_t dst_y = dst.y0;
|
||||
|
||||
int16_t src_x = 0;
|
||||
int16_t src_y = 0;
|
||||
|
||||
if (bitmap != NULL) {
|
||||
src_x += bitmap->offset.x;
|
||||
src_y += bitmap->offset.y;
|
||||
|
||||
// Normalize negative x-offset of bitmap
|
||||
if (src_x < 0) {
|
||||
dst_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
|
||||
// Normalize negative y-offset of src bitmap
|
||||
if (src_y < 0) {
|
||||
dst_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize negative top-left of destination rectangle
|
||||
if (dst_x < 0) {
|
||||
src_x -= dst_x;
|
||||
dst_x = 0;
|
||||
}
|
||||
|
||||
if (dst_y < 0) {
|
||||
src_y -= dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
|
||||
// Calculate dimension of effective rectangle
|
||||
int16_t width = MIN(DISPLAY_RESX, dst.x1) - dst_x;
|
||||
int16_t height = MIN(DISPLAY_RESY, dst.y1) - dst_y;
|
||||
|
||||
if (bitmap != NULL) {
|
||||
width = MIN(width, bitmap->size.x - src_x);
|
||||
height = MIN(height, bitmap->size.y - src_y);
|
||||
}
|
||||
|
||||
gl_clip_t clip = {
|
||||
.dst_x = dst_x,
|
||||
.dst_y = dst_y,
|
||||
.src_x = src_x,
|
||||
.src_y = src_y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
void gl_clear(void) {
|
||||
gl_bitblt_t bb = {
|
||||
// Destination bitmap
|
||||
.height = DISPLAY_RESX,
|
||||
.width = DISPLAY_RESY,
|
||||
.dst_row = NULL,
|
||||
.dst_x = 0,
|
||||
.dst_y = 0,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_fg = 0,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
display_fill(&bb);
|
||||
}
|
||||
|
||||
void gl_draw_bar(gl_rect_t rect, gl_color_t color) {
|
||||
gl_clip_t clip = gl_clip(rect, NULL);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl_bitblt_t bb = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = NULL,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_fg = color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
display_fill(&bb);
|
||||
}
|
||||
|
||||
void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap) {
|
||||
gl_clip_t clip = gl_clip(rect, bitmap);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl_bitblt_t bb = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = NULL,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.src_y,
|
||||
.src_x = clip.src_x,
|
||||
.src_y = clip.src_y,
|
||||
.src_stride = bitmap->stride,
|
||||
.src_fg = bitmap->fg_color,
|
||||
.src_bg = bitmap->bg_color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
#if TREZOR_FONT_BPP == 1
|
||||
if (bitmap->format == GL_FORMAT_MONO1P) {
|
||||
display_copy_mono1p(&bb);
|
||||
}
|
||||
#endif
|
||||
#if TREZOR_FONT_BPP == 4
|
||||
if (bitmap->format == GL_FORMAT_MONO4) {
|
||||
display_copy_mono4(&bb);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TREZOR_FONT_BPP == 1
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO1P
|
||||
#define GLYPH_STRIDE(w) (((w) + 7) / 8)
|
||||
#elif TREZOR_FONT_BPP == 2
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO2
|
||||
#define GLYPH_STRIDE(w) (((w) + 3) / 4)
|
||||
#elif TREZOR_FONT_BPP == 4
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO4
|
||||
#define GLYPH_STRIDE(w) (((w) + 1) / 2)
|
||||
#elif TREZOR_FONT_BPP == 8
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO8
|
||||
#define GLYPH_STRIDE(w) (w)
|
||||
#else
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#endif
|
||||
|
||||
#define GLYPH_WIDTH(g) ((g)[0])
|
||||
#define GLYPH_HEIGHT(g) ((g)[1])
|
||||
#define GLYPH_ADVANCE(g) ((g)[2])
|
||||
#define GLYPH_BEARING_X(g) ((g)[3])
|
||||
#define GLYPH_BEARING_Y(g) ((g)[4])
|
||||
#define GLYPH_DATA(g) ((void*)&(g)[5])
|
||||
|
||||
void gl_draw_text(gl_offset_t pos, const char* text, size_t maxlen,
|
||||
const gl_text_attr_t* attr) {
|
||||
if (text == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl_bitmap_t bitmap = {
|
||||
.format = GLYPH_FORMAT,
|
||||
.fg_color = attr->fg_color,
|
||||
.bg_color = attr->bg_color,
|
||||
};
|
||||
|
||||
int max_height = font_max_height(attr->font);
|
||||
int baseline = font_baseline(attr->font);
|
||||
|
||||
for (int i = 0; i < maxlen; i++) {
|
||||
uint8_t ch = (uint8_t)text[i];
|
||||
|
||||
if (ch == 0 || pos.x >= DISPLAY_RESX) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t* glyph = font_get_glyph(attr->font, ch);
|
||||
|
||||
if (glyph == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitmap.ptr = GLYPH_DATA(glyph);
|
||||
bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
|
||||
bitmap.size.x = GLYPH_WIDTH(glyph);
|
||||
bitmap.size.y = GLYPH_HEIGHT(glyph);
|
||||
|
||||
bitmap.offset.x = -GLYPH_BEARING_X(glyph);
|
||||
bitmap.offset.y = -(max_height - baseline - GLYPH_BEARING_Y(glyph));
|
||||
|
||||
gl_draw_bitmap(gl_rect(pos.x, pos.y, DISPLAY_RESX, DISPLAY_RESY), &bitmap);
|
||||
|
||||
pos.x += GLYPH_ADVANCE(glyph);
|
||||
}
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// emulation of legacy functions
|
||||
|
||||
void display_clear(void) { gl_clear(); }
|
||||
|
||||
void display_bar(int x, int y, int w, int h, uint16_t c) {
|
||||
gl_draw_bar(gl_rect_wh(x, y, w, h), c);
|
||||
}
|
||||
|
||||
void display_text(int x, int y, const char* text, int textlen, int font,
|
||||
uint16_t fg_color, uint16_t bg_color) {
|
||||
gl_text_attr_t attr = {
|
||||
.font = font,
|
||||
.fg_color = fg_color,
|
||||
.bg_color = bg_color,
|
||||
};
|
||||
|
||||
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
|
||||
gl_draw_text(gl_offset(x, y), text, maxlen, &attr);
|
||||
}
|
||||
|
||||
void display_text_center(int x, int y, const char* text, int textlen, int font,
|
||||
uint16_t fg_color, uint16_t bg_color) {
|
||||
gl_text_attr_t attr = {
|
||||
.font = font,
|
||||
.fg_color = fg_color,
|
||||
.bg_color = bg_color,
|
||||
};
|
||||
|
||||
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
|
||||
int w = font_text_width(font, text, textlen);
|
||||
gl_draw_text(gl_offset(x - w / 2, y), text, maxlen, &attr);
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GL_DRAW_H
|
||||
#define GL_DRAW_H
|
||||
|
||||
#include "gl_color.h"
|
||||
|
||||
// 2D rectangle coordinates
|
||||
//
|
||||
// `x0`, `y0` - top-left coordinates
|
||||
// `x1`, `y1` - bottom-right coordinates point (not included)
|
||||
typedef struct {
|
||||
int16_t x0;
|
||||
int16_t y0;
|
||||
int16_t x1;
|
||||
int16_t y1;
|
||||
} gl_rect_t;
|
||||
|
||||
// Builds a rectangle (`gl_rect_t`) from top-left coordinates and dimensions
|
||||
static inline gl_rect_t gl_rect_wh(int16_t x, int16_t y, int16_t w, int16_t h) {
|
||||
gl_rect_t rect = {
|
||||
.x0 = x,
|
||||
.y0 = y,
|
||||
.x1 = x + w,
|
||||
.y1 = y + h,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// Builds a rectangle (`gl_rect_t`) from top-left and bottom-right coordinates
|
||||
static inline gl_rect_t gl_rect(int16_t x0, int16_t y0, int16_t x1,
|
||||
int16_t y1) {
|
||||
gl_rect_t rect = {
|
||||
.x0 = x0,
|
||||
.y0 = y0,
|
||||
.x1 = x1,
|
||||
.y1 = y1,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// 2D offset/ coordinates
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} gl_offset_t;
|
||||
|
||||
// Builds a `gl_offset_t` structure
|
||||
static inline gl_offset_t gl_offset(int16_t x, int16_t y) {
|
||||
gl_offset_t offset = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// 2D size in pixels
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} gl_size_t;
|
||||
|
||||
// Builds a `gl_size_t` structure
|
||||
static inline gl_size_t gl_size(int16_t x, int16_t y) {
|
||||
gl_size_t size = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Format of pixels in a bitmap
|
||||
typedef enum {
|
||||
GL_FORMAT_UNKNOWN, //
|
||||
GL_FORMAT_MONO1P, // 1-bpp per pixel (packed)
|
||||
GL_FORMAT_MONO4, // 4-bpp per pixel
|
||||
GL_FORMAT_RGB565, // 16-bpp per pixel
|
||||
GL_FORMAT_RGBA8888, // 32-bpp
|
||||
} gl_format_t;
|
||||
|
||||
// 2D bitmap reference
|
||||
typedef struct {
|
||||
// pointer to top-left pixel
|
||||
void* ptr;
|
||||
// stride in bytes
|
||||
size_t stride;
|
||||
// size in pixels
|
||||
gl_size_t size;
|
||||
// format of pixels, GL_FORMAT_xxx
|
||||
uint8_t format;
|
||||
// offset used when bitmap is drawed using gl_draw_bitmap()
|
||||
gl_offset_t offset;
|
||||
// foreground color (used with MONOx formats)
|
||||
gl_color_t fg_color;
|
||||
// background color (used with MONOx formats)
|
||||
gl_color_t bg_color;
|
||||
} gl_bitmap_t;
|
||||
|
||||
// Text attributes (font and color)
|
||||
typedef struct {
|
||||
// Font identifier
|
||||
int font;
|
||||
// Foreground color
|
||||
gl_color_t fg_color;
|
||||
// Background color
|
||||
gl_color_t bg_color;
|
||||
} gl_text_attr_t;
|
||||
|
||||
// Fills a rectangle with a specified color.
|
||||
void gl_draw_bar(gl_rect_t rect, gl_color_t color);
|
||||
|
||||
// Draws a bitmap into the specified rectangle.
|
||||
//
|
||||
// The destination rectangle may not be fully filled if the source bitmap
|
||||
// is smaller then destination rectangle or if the bitmap is translated by
|
||||
// an offset partially or completely outside the destination rectangle.
|
||||
void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap);
|
||||
|
||||
// Draws a text to the specified position.
|
||||
//
|
||||
// `offset` - the most left point on the font baseline
|
||||
// `text` - utf-8 text
|
||||
// `maxlen` - maximum number of characters displayed (use SIZE_MAX when not
|
||||
// specified) `attr` - font & text color
|
||||
void gl_draw_text(gl_offset_t offset, const char* text, size_t maxlen,
|
||||
const gl_text_attr_t* attr);
|
||||
|
||||
#endif // GL_DRAW_H
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_DMA2D_BITBLT_H
|
||||
#define TREZORHAL_DMA2D_BITBLT_H
|
||||
|
||||
#include "gl_bitblt.h"
|
||||
|
||||
// Returns `true` if the specified address is accessible by DMA2D
|
||||
// and can be used by any of the following functions
|
||||
bool dma2d_accessible(const void* ptr);
|
||||
|
||||
// Waits until any pending DMA2D operation is finished
|
||||
void dma2d_wait(void);
|
||||
|
||||
// Following functions are hardware (DMA2D) accelerated versions
|
||||
// of `gl_rgb565_xxx()` and `gl_rgba8888_xxx()` function from `gl_bitblt.h`
|
||||
|
||||
void dma2d_rgb565_fill(const gl_bitblt_t* bb);
|
||||
void dma2d_rgb565_copy_mono4(const gl_bitblt_t* bb);
|
||||
void dma2d_rgb565_copy_rgb565(const gl_bitblt_t* bb);
|
||||
void dma2d_rgb565_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
void dma2d_rgba8888_fill(const gl_bitblt_t* bb);
|
||||
void dma2d_rgba8888_copy_mono4(const gl_bitblt_t* bb);
|
||||
void dma2d_rgba8888_copy_rgb565(const gl_bitblt_t* bb);
|
||||
void dma2d_rgba8888_copy_rgba8888(const gl_bitblt_t* bb);
|
||||
void dma2d_rgba8888_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
#endif // TREZORHAL_DMA2D_BITBLT_H
|
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <xdisplay.h>
|
||||
|
||||
#include "display_fb.h"
|
||||
#include "display_io.h"
|
||||
#include "display_panel.h"
|
||||
|
||||
#include "backlight_pwm.h"
|
||||
#include "supervise.h"
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
#include "bg_copy.h"
|
||||
#endif
|
||||
|
||||
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// Current display orientation (0, 90, 180, 270)
|
||||
int orientation_angle;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
|
||||
display_io_init_gpio();
|
||||
display_io_init_fmc();
|
||||
display_panel_init();
|
||||
display_panel_set_little_endian();
|
||||
backlight_pwm_init();
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
display_io_init_te_interrupt();
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
|
||||
// Reinitialize FMC to set correct timing
|
||||
// We have to do this in reinit because boardloader is fixed.
|
||||
display_io_init_fmc();
|
||||
|
||||
// Important for model T as this is not set in boardloader
|
||||
display_panel_set_little_endian();
|
||||
display_panel_init_gamma();
|
||||
backlight_pwm_reinit();
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
display_io_init_te_interrupt();
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
#ifdef XFRAMEBUFFER
|
||||
#ifndef BOARDLOADER
|
||||
bg_copy_wait();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
#ifdef XFRAMEBUFFER
|
||||
#ifndef BOARDLOADER
|
||||
// wait for DMA transfer to finish before changing backlight
|
||||
// so that we know that panel has current data
|
||||
if (backlight_pwm_get() != level && !is_mode_handler()) {
|
||||
bg_copy_wait();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return backlight_pwm_set(level);
|
||||
}
|
||||
|
||||
int display_get_backlight(void) { return backlight_pwm_get(); }
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
if (angle != drv->orientation_angle) {
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
drv->orientation_angle = angle;
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
memset(physical_frame_buffer_0, 0, sizeof(physical_frame_buffer_0));
|
||||
memset(physical_frame_buffer_1, 0, sizeof(physical_frame_buffer_1));
|
||||
#endif
|
||||
|
||||
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
|
||||
for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
|
||||
// 2 bytes per pixel because we're using RGB 5-6-5 format
|
||||
ISSUE_PIXEL_DATA(0x0000);
|
||||
}
|
||||
|
||||
display_panel_rotate(angle);
|
||||
}
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t* drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
#ifndef XFRAMEBUFFER
|
||||
void display_refresh(void) {
|
||||
// if the framebuffer is not used the implementation is empty
|
||||
}
|
||||
#endif
|
||||
|
||||
void display_wait_for_sync(void) {
|
||||
#ifdef DISPLAY_TE_PIN
|
||||
uint32_t id = display_panel_identify();
|
||||
if (id && (id != DISPLAY_ID_GC9307)) {
|
||||
// synchronize with the panel synchronization signal
|
||||
// in order to avoid visual tearing effects
|
||||
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN))
|
||||
;
|
||||
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN))
|
||||
;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_set_compatible_settings(void) { display_panel_set_big_endian(); }
|
||||
|
||||
static inline void set_window(const gl_bitblt_t* bb) {
|
||||
display_panel_set_window(bb->dst_x, bb->dst_y, bb->dst_x + bb->width - 1,
|
||||
bb->dst_y + bb->height + 1);
|
||||
}
|
||||
|
||||
void display_fill(const gl_bitblt_t* bb) {
|
||||
set_window(bb);
|
||||
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
ISSUE_PIXEL_DATA(bb->src_fg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void display_copy_rgb565(const gl_bitblt_t* bb) {
|
||||
set_window(bb);
|
||||
|
||||
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
ISSUE_PIXEL_DATA(src_ptr[x]);
|
||||
}
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void display_copy_mono1p(const gl_bitblt_t* bb) {
|
||||
set_window(bb);
|
||||
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
ISSUE_PIXEL_DATA((data & mask) ? bb->src_fg : bb->src_bg);
|
||||
}
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void display_copy_mono4(const gl_bitblt_t* bb) {
|
||||
set_window(bb);
|
||||
|
||||
const gl_color16_t* gradient = gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
|
||||
ISSUE_PIXEL_DATA(gradient[fg_lum]);
|
||||
}
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_fb.h"
|
||||
#include "display_io.h"
|
||||
#include "display_panel.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
#include "irq.h"
|
||||
#include "supervise.h"
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
#include "bg_copy.h"
|
||||
#endif
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
|
||||
#ifndef STM32U5
|
||||
#error Framebuffer only supported on STM32U5 for now
|
||||
#endif
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
__attribute__((section(".fb1")))
|
||||
ALIGN_32BYTES(uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
__attribute__((section(".fb2")))
|
||||
ALIGN_32BYTES(uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
// It's shared between bootloaders and the firmware
|
||||
__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
|
||||
0;
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
static bool pending_fb_switch = false;
|
||||
#endif
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
void DISPLAY_TE_INTERRUPT_HANDLER(void) {
|
||||
HAL_NVIC_DisableIRQ(DISPLAY_TE_INTERRUPT_NUM);
|
||||
|
||||
if (current_frame_buffer == 1) {
|
||||
bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_1,
|
||||
(uint8_t *)DISPLAY_DATA_ADDRESS,
|
||||
DISPLAY_RESX * DISPLAY_RESY * 2);
|
||||
|
||||
} else {
|
||||
bg_copy_start_const_out_8((uint8_t *)physical_frame_buffer_0,
|
||||
(uint8_t *)DISPLAY_DATA_ADDRESS,
|
||||
DISPLAY_RESX * DISPLAY_RESY * 2);
|
||||
}
|
||||
|
||||
pending_fb_switch = false;
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
|
||||
}
|
||||
|
||||
static void wait_for_fb_switch(void) {
|
||||
while (pending_fb_switch) {
|
||||
__WFI();
|
||||
}
|
||||
bg_copy_wait();
|
||||
}
|
||||
#endif
|
||||
|
||||
static void copy_fb_to_display(uint16_t *fb) {
|
||||
for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) {
|
||||
// 2 bytes per pixel because we're using RGB 5-6-5 format
|
||||
ISSUE_PIXEL_DATA(fb[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void switch_fb_manually(void) {
|
||||
// sync with the panel refresh
|
||||
while (GPIO_PIN_SET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
|
||||
}
|
||||
while (GPIO_PIN_RESET == HAL_GPIO_ReadPin(DISPLAY_TE_PORT, DISPLAY_TE_PIN)) {
|
||||
}
|
||||
|
||||
if (current_frame_buffer == 0) {
|
||||
current_frame_buffer = 1;
|
||||
copy_fb_to_display((uint16_t *)physical_frame_buffer_1);
|
||||
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
|
||||
sizeof(physical_frame_buffer_0));
|
||||
|
||||
} else {
|
||||
current_frame_buffer = 0;
|
||||
copy_fb_to_display((uint16_t *)physical_frame_buffer_0);
|
||||
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
|
||||
sizeof(physical_frame_buffer_1));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOARDLOADER
|
||||
static void switch_fb_in_backround(void) {
|
||||
if (current_frame_buffer == 0) {
|
||||
current_frame_buffer = 1;
|
||||
|
||||
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
|
||||
sizeof(physical_frame_buffer_0));
|
||||
|
||||
pending_fb_switch = true;
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
|
||||
svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM);
|
||||
} else {
|
||||
current_frame_buffer = 0;
|
||||
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
|
||||
sizeof(physical_frame_buffer_1));
|
||||
|
||||
pending_fb_switch = true;
|
||||
__HAL_GPIO_EXTI_CLEAR_FLAG(DISPLAY_TE_PIN);
|
||||
svc_enableIRQ(DISPLAY_TE_INTERRUPT_NUM);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
display_fb_info_t display_get_frame_buffer(void) {
|
||||
void *addr;
|
||||
|
||||
if (current_frame_buffer == 0) {
|
||||
addr = (void *)physical_frame_buffer_1;
|
||||
} else {
|
||||
addr = (void *)physical_frame_buffer_0;
|
||||
}
|
||||
|
||||
display_fb_info_t fb = {
|
||||
.ptr = addr,
|
||||
.stride = DISPLAY_RESX * sizeof(uint16_t),
|
||||
};
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
void display_refresh(void) {
|
||||
#ifndef BOARDLOADER
|
||||
wait_for_fb_switch();
|
||||
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
|
||||
|
||||
if (is_mode_handler()) {
|
||||
switch_fb_manually();
|
||||
} else {
|
||||
switch_fb_in_backround();
|
||||
}
|
||||
#else
|
||||
display_panel_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1);
|
||||
switch_fb_manually();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // XFRAMEBUFFER
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
#define TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
|
||||
// Size of the physical frame buffer in bytes
|
||||
#define PHYSICAL_FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2)
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
//
|
||||
// Both frame buffers layes in the fixed addresses that
|
||||
// are shared between bootloaders and the firmware.
|
||||
extern uint8_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
extern uint8_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
//
|
||||
// The variable address is shared between bootloaders and the firmware
|
||||
extern uint32_t current_frame_buffer;
|
||||
|
||||
#endif // XFRAMEBUFFER
|
||||
|
||||
#endif // TREZOR_HAL_DISPLAY_INTERNAL_H
|
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_io.h"
|
||||
#include "irq.h"
|
||||
|
||||
__IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS =
|
||||
(__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE);
|
||||
__IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS =
|
||||
(__IO DISP_MEM_TYPE *const)((uint32_t)DISPLAY_MEMORY_BASE |
|
||||
(DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN));
|
||||
|
||||
void display_io_init_gpio(void) {
|
||||
// init peripherals
|
||||
__HAL_RCC_GPIOE_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_FMC_CLK_ENABLE();
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
// LCD_RST/PC14
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_14;
|
||||
// default to keeping display in reset
|
||||
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
|
||||
#ifdef DISPLAY_TE_PIN
|
||||
// LCD_FMARK (tearing effect)
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Pin = DISPLAY_TE_PIN;
|
||||
HAL_GPIO_Init(DISPLAY_TE_PORT, &GPIO_InitStructure);
|
||||
#endif
|
||||
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF12_FMC;
|
||||
// LCD_CS/PD7 LCD_RS/PD11 LCD_RD/PD4 LCD_WR/PD5
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_11 | GPIO_PIN_4 | GPIO_PIN_5;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
// LCD_D0/PD14 LCD_D1/PD15 LCD_D2/PD0 LCD_D3/PD1
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_14 | GPIO_PIN_15 | GPIO_PIN_0 | GPIO_PIN_1;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
// LCD_D4/PE7 LCD_D5/PE8 LCD_D6/PE9 LCD_D7/PE10
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
// LCD_D8/PE11 LCD_D9/PE12 LCD_D10/PE13 LCD_D11/PE14
|
||||
GPIO_InitStructure.Pin =
|
||||
GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14;
|
||||
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
// LCD_D12/PE15
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_15;
|
||||
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
|
||||
// LCD_D13/PD8 LCD_D14/PD9 LCD_D15/PD10
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_io_init_fmc(void) {
|
||||
// Reference UM1725 "Description of STM32F4 HAL and LL drivers",
|
||||
// section 64.2.1 "How to use this driver"
|
||||
SRAM_HandleTypeDef external_display_data_sram = {0};
|
||||
external_display_data_sram.Instance = FMC_NORSRAM_DEVICE;
|
||||
external_display_data_sram.Extended = FMC_NORSRAM_EXTENDED_DEVICE;
|
||||
external_display_data_sram.Init.NSBank = FMC_NORSRAM_BANK1;
|
||||
external_display_data_sram.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE;
|
||||
external_display_data_sram.Init.MemoryType = FMC_MEMORY_TYPE_SRAM;
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
external_display_data_sram.Init.MemoryDataWidth =
|
||||
FMC_NORSRAM_MEM_BUS_WIDTH_16;
|
||||
#elif USE_DISP_I8080_8BIT_DW
|
||||
external_display_data_sram.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_8;
|
||||
#endif
|
||||
external_display_data_sram.Init.BurstAccessMode =
|
||||
FMC_BURST_ACCESS_MODE_DISABLE;
|
||||
external_display_data_sram.Init.WaitSignalPolarity =
|
||||
FMC_WAIT_SIGNAL_POLARITY_LOW;
|
||||
external_display_data_sram.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
|
||||
external_display_data_sram.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
|
||||
external_display_data_sram.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
|
||||
external_display_data_sram.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
|
||||
external_display_data_sram.Init.AsynchronousWait =
|
||||
FMC_ASYNCHRONOUS_WAIT_DISABLE;
|
||||
external_display_data_sram.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
|
||||
external_display_data_sram.Init.ContinuousClock =
|
||||
FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
|
||||
external_display_data_sram.Init.PageSize = FMC_PAGE_SIZE_NONE;
|
||||
|
||||
// reference RM0090 section 37.5 Table 259, 37.5.4, Mode 1 SRAM, and 37.5.6
|
||||
FMC_NORSRAM_TimingTypeDef normal_mode_timing = {0};
|
||||
normal_mode_timing.AddressSetupTime = 5;
|
||||
normal_mode_timing.AddressHoldTime = 1; // don't care
|
||||
normal_mode_timing.DataSetupTime = 6;
|
||||
normal_mode_timing.BusTurnAroundDuration = 0; // don't care
|
||||
normal_mode_timing.CLKDivision = 2; // don't care
|
||||
normal_mode_timing.DataLatency = 2; // don't care
|
||||
normal_mode_timing.AccessMode = FMC_ACCESS_MODE_A;
|
||||
|
||||
HAL_SRAM_Init(&external_display_data_sram, &normal_mode_timing, NULL);
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_TE_INTERRUPT_HANDLER
|
||||
void display_io_init_te_interrupt(void) {
|
||||
EXTI_HandleTypeDef EXTI_Handle = {0};
|
||||
EXTI_ConfigTypeDef EXTI_Config = {0};
|
||||
EXTI_Config.GPIOSel = DISPLAY_TE_INTERRUPT_GPIOSEL;
|
||||
EXTI_Config.Line = DISPLAY_TE_INTERRUPT_EXTI_LINE;
|
||||
EXTI_Config.Mode = EXTI_MODE_INTERRUPT;
|
||||
EXTI_Config.Trigger = EXTI_TRIGGER_RISING;
|
||||
HAL_EXTI_SetConfigLine(&EXTI_Handle, &EXTI_Config);
|
||||
|
||||
// setup interrupt for tearing effect pin
|
||||
HAL_NVIC_SetPriority(DISPLAY_TE_INTERRUPT_NUM, IRQ_PRI_DMA, 0);
|
||||
}
|
||||
#endif
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_DISPLAY_IO_H
|
||||
#define TREZORHAL_DISPLAY_IO_H
|
||||
|
||||
#include STM32_HAL_H
|
||||
#include TREZOR_BOARD
|
||||
|
||||
void display_io_init_gpio(void);
|
||||
void display_io_init_fmc(void);
|
||||
void display_io_init_te_interrupt(void);
|
||||
|
||||
#ifndef FMC_BANK1
|
||||
#define FMC_BANK1 0x60000000U
|
||||
#endif
|
||||
|
||||
#define DISPLAY_MEMORY_BASE FMC_BANK1
|
||||
#define DISPLAY_MEMORY_PIN 16
|
||||
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
#define DISPLAY_ADDR_SHIFT 2
|
||||
#define DISP_MEM_TYPE uint16_t
|
||||
#elif USE_DISP_I8080_8BIT_DW
|
||||
#define DISPLAY_ADDR_SHIFT 1
|
||||
#define DISP_MEM_TYPE uint8_t
|
||||
#else
|
||||
#error "Unsupported display interface"
|
||||
#endif
|
||||
|
||||
/*#define DISPLAY_CMD_ADDRESS ((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE))
|
||||
#define DISPLAY_DATA_ADDRESS \
|
||||
((__IO DISP_MEM_TYPE *)(DISPLAY_MEMORY_BASE | \
|
||||
(DISPLAY_ADDR_SHIFT << DISPLAY_MEMORY_PIN)))
|
||||
*/
|
||||
|
||||
extern __IO DISP_MEM_TYPE *const DISPLAY_CMD_ADDRESS;
|
||||
extern __IO DISP_MEM_TYPE *const DISPLAY_DATA_ADDRESS;
|
||||
|
||||
#define ISSUE_CMD_BYTE(X) (*(DISPLAY_CMD_ADDRESS) = (X))
|
||||
#define ISSUE_DATA_BYTE(X) (*(DISPLAY_DATA_ADDRESS) = (X))
|
||||
|
||||
#ifdef USE_DISP_I8080_16BIT_DW
|
||||
#define ISSUE_PIXEL_DATA(X) DATA(X)
|
||||
#elif USE_DISP_I8080_8BIT_DW
|
||||
#define ISSUE_PIXEL_DATA(X) \
|
||||
ISSUE_DATA_BYTE((X)&0xFF); \
|
||||
ISSUE_DATA_BYTE((X) >> 8)
|
||||
#endif
|
||||
|
||||
#endif // TREZORHAL_DISPLAY_IO_H
|
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
// Window padding (correction) when using 90dg or 270dg orientation
|
||||
// (internally the display is 240x320 but we use only 240x240)
|
||||
static display_padding_t g_window_padding;
|
||||
|
||||
#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_panel_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) {
|
||||
x0 += g_window_padding.x;
|
||||
x1 += g_window_padding.x;
|
||||
y0 += g_window_padding.y;
|
||||
y1 += g_window_padding.y;
|
||||
|
||||
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_panel_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, &g_window_padding);
|
||||
} else {
|
||||
lx154a2422_rotate(angle, &g_window_padding);
|
||||
}
|
||||
#else
|
||||
lx154a2422_rotate(angle, &g_window_padding);
|
||||
#endif
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_ST7789_PANEL_H
|
||||
#define TREZORHAL_ST7789_PANEL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// section "9.1.3 RDDID (04h): Read Display ID"
|
||||
// of ST7789V datasheet
|
||||
#define DISPLAY_ID_ST7789V 0x858552U
|
||||
// section "6.2.1. Read display identification information (04h)"
|
||||
// of GC9307 datasheet
|
||||
#define DISPLAY_ID_GC9307 0x009307U
|
||||
// section "8.3.23 Read ID4 (D3h)"
|
||||
// of ILI9341V datasheet
|
||||
#define DISPLAY_ID_ILI9341V 0x009341U
|
||||
|
||||
typedef struct {
|
||||
uint16_t x;
|
||||
uint16_t y;
|
||||
} display_padding_t;
|
||||
|
||||
// Identifies the connected display panel and
|
||||
// returns one of DISPLAY_ID_xxx constant
|
||||
uint32_t display_panel_identify(void);
|
||||
bool display_panel_is_inverted();
|
||||
|
||||
void display_panel_init(void);
|
||||
void display_panel_init_gamma(void);
|
||||
void display_panel_set_little_endian(void);
|
||||
void display_panel_set_big_endian(void);
|
||||
|
||||
void display_panel_sleep(void);
|
||||
void display_panel_unsleep(void);
|
||||
void display_panel_set_window(uint16_t x0, uint16_t y0, uint16_t x1,
|
||||
uint16_t y1);
|
||||
void display_panel_rotate(int angle);
|
||||
|
||||
#endif // TREZORHAL_ST7789_PANEL_H
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../display_io.h"
|
||||
|
||||
void _154a_init_seq(void) {
|
||||
// most recent manual: https://www.newhavendisplay.com/app_notes/ILI9341.pdf
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// Display Function Control: gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xB6);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0xC2);
|
||||
ISSUE_DATA_BYTE(0x27);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// Interface Control: XOR BGR as ST7789V does
|
||||
ISSUE_CMD_BYTE(0xF6);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x30);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// the above config is the most important and definitely necessary
|
||||
|
||||
ISSUE_CMD_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0xC1);
|
||||
ISSUE_DATA_BYTE(0x30);
|
||||
|
||||
ISSUE_CMD_BYTE(0xED);
|
||||
ISSUE_DATA_BYTE(0x64);
|
||||
ISSUE_DATA_BYTE(0x03);
|
||||
ISSUE_DATA_BYTE(0x12);
|
||||
ISSUE_DATA_BYTE(0x81);
|
||||
|
||||
ISSUE_CMD_BYTE(0xE8);
|
||||
ISSUE_DATA_BYTE(0x85);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x7A);
|
||||
|
||||
ISSUE_CMD_BYTE(0xF7);
|
||||
ISSUE_DATA_BYTE(0x20);
|
||||
|
||||
ISSUE_CMD_BYTE(0xEA);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// power control VRH[5:0]
|
||||
ISSUE_CMD_BYTE(0xC0);
|
||||
ISSUE_DATA_BYTE(0x23);
|
||||
|
||||
// power control SAP[2:0] BT[3:0]
|
||||
ISSUE_CMD_BYTE(0xC1);
|
||||
ISSUE_DATA_BYTE(0x12);
|
||||
|
||||
// vcm control 1
|
||||
ISSUE_CMD_BYTE(0xC5);
|
||||
ISSUE_DATA_BYTE(0x60);
|
||||
ISSUE_DATA_BYTE(0x44);
|
||||
|
||||
// vcm control 2
|
||||
ISSUE_CMD_BYTE(0xC7);
|
||||
ISSUE_DATA_BYTE(0x8A);
|
||||
|
||||
// framerate
|
||||
ISSUE_CMD_BYTE(0xB1);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
|
||||
// 3 gamma func disable
|
||||
ISSUE_CMD_BYTE(0xF2);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// gamma curve 1
|
||||
ISSUE_CMD_BYTE(0xE0);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
ISSUE_DATA_BYTE(0x2F);
|
||||
ISSUE_DATA_BYTE(0x2C);
|
||||
ISSUE_DATA_BYTE(0x0B);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x56);
|
||||
ISSUE_DATA_BYTE(0xD9);
|
||||
ISSUE_DATA_BYTE(0x4A);
|
||||
ISSUE_DATA_BYTE(0x0B);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x05);
|
||||
ISSUE_DATA_BYTE(0x0C);
|
||||
ISSUE_DATA_BYTE(0x06);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// gamma curve 2
|
||||
ISSUE_CMD_BYTE(0xE1);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x13);
|
||||
ISSUE_DATA_BYTE(0x04);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x06);
|
||||
ISSUE_DATA_BYTE(0x25);
|
||||
ISSUE_DATA_BYTE(0x26);
|
||||
ISSUE_DATA_BYTE(0x3B);
|
||||
ISSUE_DATA_BYTE(0x04);
|
||||
ISSUE_DATA_BYTE(0x0B);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x33);
|
||||
ISSUE_DATA_BYTE(0x39);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _154A_H_
|
||||
#define _154A_H_
|
||||
|
||||
// ILI9341 IC controller
|
||||
|
||||
void _154a_init_seq(void);
|
||||
|
||||
#endif
|
@ -0,0 +1,82 @@
|
||||
|
||||
#include "../display_io.h"
|
||||
|
||||
void lx154a2411_gamma(void) {
|
||||
// positive voltage correction
|
||||
ISSUE_CMD_BYTE(0xE0);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x03);
|
||||
ISSUE_DATA_BYTE(0x08);
|
||||
ISSUE_DATA_BYTE(0x0E);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x3B);
|
||||
ISSUE_DATA_BYTE(0x44);
|
||||
ISSUE_DATA_BYTE(0x4C);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x16);
|
||||
ISSUE_DATA_BYTE(0x15);
|
||||
ISSUE_DATA_BYTE(0x1E);
|
||||
ISSUE_DATA_BYTE(0x21);
|
||||
|
||||
// negative voltage correction
|
||||
ISSUE_CMD_BYTE(0xE1);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x03);
|
||||
ISSUE_DATA_BYTE(0x08);
|
||||
ISSUE_DATA_BYTE(0x0E);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x3B);
|
||||
ISSUE_DATA_BYTE(0x54);
|
||||
ISSUE_DATA_BYTE(0x4C);
|
||||
ISSUE_DATA_BYTE(0x2B);
|
||||
ISSUE_DATA_BYTE(0x16);
|
||||
ISSUE_DATA_BYTE(0x15);
|
||||
ISSUE_DATA_BYTE(0x1E);
|
||||
ISSUE_DATA_BYTE(0x21);
|
||||
}
|
||||
|
||||
void lx154a2411_init_seq(void) {
|
||||
// most recent manual:
|
||||
// https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// CMD2EN: Commands in command table 2 can be executed when EXTC level is Low
|
||||
ISSUE_CMD_BYTE(0xDF);
|
||||
ISSUE_DATA_BYTE(0x5A);
|
||||
ISSUE_DATA_BYTE(0x69);
|
||||
ISSUE_DATA_BYTE(0x02);
|
||||
ISSUE_DATA_BYTE(0x01);
|
||||
|
||||
// LCMCTRL: LCM Control: XOR RGB setting
|
||||
ISSUE_CMD_BYTE(0xC0);
|
||||
ISSUE_DATA_BYTE(0x20);
|
||||
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.;
|
||||
// gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
|
||||
// INVOFF (20h): Display Inversion Off
|
||||
// INVON (21h): Display Inversion On
|
||||
ISSUE_CMD_BYTE(0x20);
|
||||
|
||||
// the above config is the most important and definitely necessary
|
||||
|
||||
// PWCTRL1: Power Control 1
|
||||
ISSUE_CMD_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0xA4);
|
||||
ISSUE_DATA_BYTE(0xA1);
|
||||
|
||||
lx154a2411_gamma();
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef LX154A2411_H_
|
||||
#define LX154A2411_H_
|
||||
|
||||
// ST7789_V IC controller
|
||||
void lx154a2411_gamma(void);
|
||||
void lx154a2411_init_seq(void);
|
||||
|
||||
#endif
|
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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 "lx154a2422.h"
|
||||
|
||||
#include "../display_io.h"
|
||||
|
||||
void lx154a2422_gamma(void) {
|
||||
// positive voltage correction
|
||||
ISSUE_CMD_BYTE(0xE0);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x26);
|
||||
ISSUE_DATA_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(0x34);
|
||||
ISSUE_DATA_BYTE(0x4D);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
ISSUE_DATA_BYTE(0x13);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x2F);
|
||||
ISSUE_DATA_BYTE(0x34);
|
||||
|
||||
// negative voltage correction
|
||||
ISSUE_CMD_BYTE(0xE1);
|
||||
ISSUE_DATA_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x09);
|
||||
ISSUE_DATA_BYTE(0x26);
|
||||
ISSUE_DATA_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(0x53);
|
||||
ISSUE_DATA_BYTE(0x4C);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x14);
|
||||
ISSUE_DATA_BYTE(0x2F);
|
||||
ISSUE_DATA_BYTE(0x34);
|
||||
}
|
||||
|
||||
void lx154a2422_init_seq(void) {
|
||||
// most recent manual:
|
||||
// https://www.newhavendisplay.com/appnotes/datasheets/LCDs/ST7789V.pdf
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// CMD2EN: Commands in command table 2 can be executed when EXTC level is Low
|
||||
ISSUE_CMD_BYTE(0xDF);
|
||||
ISSUE_DATA_BYTE(0x5A);
|
||||
ISSUE_DATA_BYTE(0x69);
|
||||
ISSUE_DATA_BYTE(0x02);
|
||||
ISSUE_DATA_BYTE(0x01);
|
||||
|
||||
// LCMCTRL: LCM Control: XOR RGB setting
|
||||
ISSUE_CMD_BYTE(0xC0);
|
||||
ISSUE_DATA_BYTE(0x20);
|
||||
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is gate 80.;
|
||||
// gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
|
||||
// INVOFF (20h): Display Inversion Off
|
||||
// INVON (21h): Display Inversion On
|
||||
ISSUE_CMD_BYTE(0x21);
|
||||
|
||||
// the above config is the most important and definitely necessary
|
||||
|
||||
// PWCTRL1: Power Control 1
|
||||
ISSUE_CMD_BYTE(0xD0);
|
||||
ISSUE_DATA_BYTE(0xA4);
|
||||
ISSUE_DATA_BYTE(0xA1);
|
||||
|
||||
lx154a2422_gamma();
|
||||
}
|
||||
|
||||
void lx154a2422_rotate(int degrees, display_padding_t* padding) {
|
||||
uint16_t shift = 0;
|
||||
char BX = 0, BY = 0;
|
||||
|
||||
#define RGB (1 << 3)
|
||||
#define ML (1 << 4) // vertical refresh order
|
||||
#define MH (1 << 2) // horizontal refresh order
|
||||
#define MV (1 << 5)
|
||||
#define MX (1 << 6)
|
||||
#define MY (1 << 7)
|
||||
// MADCTL: Memory Data Access Control - reference:
|
||||
// section 8.12 in the ST7789V manual
|
||||
uint8_t display_command_parameter = 0;
|
||||
switch (degrees) {
|
||||
case 0:
|
||||
display_command_parameter = 0;
|
||||
BY = 0;
|
||||
break;
|
||||
case 90:
|
||||
display_command_parameter = MV | MX | MH | ML;
|
||||
BX = 1;
|
||||
shift = 1;
|
||||
break;
|
||||
case 180:
|
||||
display_command_parameter = MX | MY | MH | ML;
|
||||
BY = 0;
|
||||
shift = 1;
|
||||
break;
|
||||
case 270:
|
||||
display_command_parameter = MV | MY;
|
||||
BX = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ISSUE_CMD_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(display_command_parameter);
|
||||
|
||||
if (shift) {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
} else {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
}
|
||||
|
||||
padding->x = BX ? (320 - DISPLAY_RESY) : 0;
|
||||
padding->y = BY ? (320 - DISPLAY_RESY) : 0;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 LX154A2422_H_
|
||||
#define LX154A2422_H_
|
||||
|
||||
#include "../display_panel.h"
|
||||
|
||||
void lx154a2422_init_seq(void);
|
||||
void lx154a2422_gamma(void);
|
||||
void lx154a2422_rotate(int degrees, display_padding_t* padding);
|
||||
|
||||
#endif
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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 "tf15411a.h"
|
||||
#include "../display_io.h"
|
||||
|
||||
void tf15411a_init_seq(void) {
|
||||
// Inter Register Enable1
|
||||
ISSUE_CMD_BYTE(0xFE);
|
||||
|
||||
// Inter Register Enable2
|
||||
ISSUE_CMD_BYTE(0xEF);
|
||||
|
||||
// TEON: Tearing Effect Line On; V-blanking only
|
||||
ISSUE_CMD_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// COLMOD: Interface Pixel format; 65K color: 16-bit/pixel (RGB 5-6-5 bits
|
||||
// input)
|
||||
ISSUE_CMD_BYTE(0x3A);
|
||||
ISSUE_DATA_BYTE(0x55);
|
||||
|
||||
// Frame Rate
|
||||
// ISSUE_CMD_BYTE(0xE8); ISSUE_DATA_BYTE(0x12); ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
// Power Control 2
|
||||
ISSUE_CMD_BYTE(0xC3);
|
||||
ISSUE_DATA_BYTE(0x27);
|
||||
|
||||
// Power Control 3
|
||||
ISSUE_CMD_BYTE(0xC4);
|
||||
ISSUE_DATA_BYTE(0x18);
|
||||
|
||||
// Power Control 4
|
||||
ISSUE_CMD_BYTE(0xC9);
|
||||
ISSUE_DATA_BYTE(0x1F);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC5);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC6);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC7);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
|
||||
ISSUE_CMD_BYTE(0xC8);
|
||||
ISSUE_DATA_BYTE(0x01);
|
||||
|
||||
ISSUE_CMD_BYTE(0xFF);
|
||||
ISSUE_DATA_BYTE(0x62);
|
||||
|
||||
ISSUE_CMD_BYTE(0x99);
|
||||
ISSUE_DATA_BYTE(0x3E);
|
||||
|
||||
ISSUE_CMD_BYTE(0x9D);
|
||||
ISSUE_DATA_BYTE(0x4B);
|
||||
|
||||
ISSUE_CMD_BYTE(0x8E);
|
||||
ISSUE_DATA_BYTE(0x0F);
|
||||
|
||||
// SET_GAMMA1
|
||||
ISSUE_CMD_BYTE(0xF0);
|
||||
ISSUE_DATA_BYTE(0x8F);
|
||||
ISSUE_DATA_BYTE(0x1B);
|
||||
ISSUE_DATA_BYTE(0x05);
|
||||
ISSUE_DATA_BYTE(0x06);
|
||||
ISSUE_DATA_BYTE(0x07);
|
||||
ISSUE_DATA_BYTE(0x42);
|
||||
|
||||
// SET_GAMMA3
|
||||
ISSUE_CMD_BYTE(0xF2);
|
||||
ISSUE_DATA_BYTE(0x5C);
|
||||
ISSUE_DATA_BYTE(0x1F);
|
||||
ISSUE_DATA_BYTE(0x12);
|
||||
ISSUE_DATA_BYTE(0x10);
|
||||
ISSUE_DATA_BYTE(0x07);
|
||||
ISSUE_DATA_BYTE(0x43);
|
||||
|
||||
// SET_GAMMA2
|
||||
ISSUE_CMD_BYTE(0xF1);
|
||||
ISSUE_DATA_BYTE(0x59);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x37);
|
||||
ISSUE_DATA_BYTE(0x8F);
|
||||
|
||||
// SET_GAMMA4
|
||||
ISSUE_CMD_BYTE(0xF3);
|
||||
ISSUE_DATA_BYTE(0x58);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0xCF);
|
||||
ISSUE_DATA_BYTE(0x35);
|
||||
ISSUE_DATA_BYTE(0x37);
|
||||
ISSUE_DATA_BYTE(0x8F);
|
||||
}
|
||||
|
||||
void tf15411a_rotate(int degrees, display_padding_t* padding) {
|
||||
uint16_t shift = 0;
|
||||
char BX = 0, BY = 0;
|
||||
|
||||
#define RGB (1 << 3)
|
||||
#define ML (1 << 4) // vertical refresh order
|
||||
#define MH (1 << 2) // horizontal refresh order
|
||||
#define MV (1 << 5)
|
||||
#define MX (1 << 6)
|
||||
#define MY (1 << 7)
|
||||
// MADCTL: Memory Data Access Control - reference:
|
||||
// section 9.3 in the ILI9341 manual
|
||||
// section 6.2.18 in the GC9307 manual
|
||||
// section 8.12 in the ST7789V manual
|
||||
uint8_t display_command_parameter = 0;
|
||||
switch (degrees) {
|
||||
case 0:
|
||||
display_command_parameter = 0;
|
||||
BY = 1;
|
||||
break;
|
||||
case 90:
|
||||
display_command_parameter = MV | MX | MH | ML;
|
||||
BX = 0;
|
||||
shift = 1;
|
||||
break;
|
||||
case 180:
|
||||
display_command_parameter = MX | MY | MH | ML;
|
||||
BY = 1;
|
||||
shift = 1;
|
||||
break;
|
||||
case 270:
|
||||
display_command_parameter = MV | MY;
|
||||
BX = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
display_command_parameter ^= RGB | MY; // XOR RGB and MY settings
|
||||
|
||||
ISSUE_CMD_BYTE(0x36);
|
||||
ISSUE_DATA_BYTE(display_command_parameter);
|
||||
|
||||
if (shift) {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x00);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
} else {
|
||||
// GATECTRL: Gate Control; NL = 240 gate lines, first scan line is
|
||||
// gate 80.; gate scan direction 319 -> 0
|
||||
ISSUE_CMD_BYTE(0xE4);
|
||||
ISSUE_DATA_BYTE(0x1D);
|
||||
ISSUE_DATA_BYTE(0x0A);
|
||||
ISSUE_DATA_BYTE(0x11);
|
||||
}
|
||||
|
||||
padding->x = BX ? (320 - DISPLAY_RESY) : 0;
|
||||
padding->y = BY ? (320 - DISPLAY_RESY) : 0;
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TF15411A_H_
|
||||
#define TF15411A_H_
|
||||
|
||||
#include "../display_panel.h"
|
||||
|
||||
// GC9307 IC controller
|
||||
|
||||
void tf15411a_init_seq(void);
|
||||
void tf15411a_rotate(int degrees, display_padding_t* padding);
|
||||
|
||||
#endif
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_internal.h"
|
||||
#include "ili9341_spi.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 320)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// Pointer to the frame buffer
|
||||
uint16_t *framebuf;
|
||||
// Current display orientation (0, 90, 180, 270)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
drv->framebuf = (uint16_t *)FRAME_BUFFER_ADDR;
|
||||
|
||||
// Initialize LTDC controller
|
||||
BSP_LCD_Init();
|
||||
// Initialize external display controller
|
||||
ili9341_init();
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
drv->framebuf = (uint16_t *)FRAME_BUFFER_ADDR;
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
// Not used and intentionally left empty
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
// Just emulation, not doing anything
|
||||
drv->backlight_level = level;
|
||||
return level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
// Just emulation, not doing anything
|
||||
drv->orientation_angle = angle;
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
display_fb_info_t display_get_frame_buffer(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
display_fb_info_t fb = {
|
||||
.ptr = (void *)drv->framebuf,
|
||||
.stride = DISPLAY_RESX * sizeof(uint16_t),
|
||||
};
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
void display_refresh(void) {
|
||||
// Do nothing as using just a single frame buffer
|
||||
}
|
||||
|
||||
void display_set_compatible_settings() {}
|
||||
|
||||
void display_fill(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y);
|
||||
bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
|
||||
|
||||
gl_rgb565_fill(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_rgb565(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y);
|
||||
bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
|
||||
|
||||
gl_rgb565_copy_rgb565(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_mono4(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row = drv->framebuf + (DISPLAY_RESX * bb_new.dst_y);
|
||||
bb_new.dst_stride = DISPLAY_RESX * sizeof(uint16_t);
|
||||
|
||||
gl_rgb565_copy_mono4(&bb_new);
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_DISPLAY_INTERNAL_H
|
||||
#define TREZORHAL_DISPLAY_INTERNAL_H
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "sdram.h"
|
||||
|
||||
// Frame buffer address in external SDRAM
|
||||
#define FRAME_BUFFER_ADDR ((uint32_t)SDRAM_DEVICE_ADDR)
|
||||
// Frame buffer size (16-bit per pixel RGB565)
|
||||
#define FRAME_BUFFER_SIZE (DISPLAY_RESX * DISPLAY_RESY * 2)
|
||||
|
||||
// Initializes LTDC controller and I/O pins
|
||||
void BSP_LCD_Init(void);
|
||||
|
||||
#endif // TREZORHAL_DISPLAY_INTERNAL_H
|
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_internal.h"
|
||||
#include "ili9341_spi.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
#define MAX_LAYER_NUMBER 2
|
||||
|
||||
LTDC_HandleTypeDef LtdcHandler;
|
||||
static RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
|
||||
|
||||
/* Default LCD configuration with LCD Layer 1 */
|
||||
uint32_t ActiveLayer = 0;
|
||||
|
||||
/**
|
||||
* @brief Initializes the LCD layers.
|
||||
* @param LayerIndex: the layer foreground or background.
|
||||
* @param FB_Address: the layer frame buffer.
|
||||
*/
|
||||
void BSP_LCD_LayerDefaultInit(uint16_t LayerIndex, uint32_t FB_Address) {
|
||||
LTDC_LayerCfgTypeDef Layercfg;
|
||||
|
||||
/* Layer Init */
|
||||
Layercfg.WindowX0 = 0;
|
||||
Layercfg.WindowX1 = DISPLAY_RESX;
|
||||
Layercfg.WindowY0 = 0;
|
||||
Layercfg.WindowY1 = DISPLAY_RESY;
|
||||
Layercfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
|
||||
Layercfg.FBStartAdress = FB_Address;
|
||||
Layercfg.Alpha = 255;
|
||||
Layercfg.Alpha0 = 0;
|
||||
Layercfg.Backcolor.Blue = 0;
|
||||
Layercfg.Backcolor.Green = 0;
|
||||
Layercfg.Backcolor.Red = 0;
|
||||
Layercfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
|
||||
Layercfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
|
||||
Layercfg.ImageWidth = DISPLAY_RESX;
|
||||
Layercfg.ImageHeight = DISPLAY_RESY;
|
||||
|
||||
HAL_LTDC_ConfigLayer(&LtdcHandler, &Layercfg, LayerIndex);
|
||||
|
||||
// DrawProp[LayerIndex].BackColor = LCD_COLOR_WHITE;
|
||||
// DrawProp[LayerIndex].pFont = &Font24;
|
||||
// DrawProp[LayerIndex].TextColor = LCD_COLOR_BLACK;
|
||||
|
||||
/* Dithering activation */
|
||||
HAL_LTDC_EnableDither(&LtdcHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Selects the LCD Layer.
|
||||
* @param LayerIndex: the Layer foreground or background.
|
||||
*/
|
||||
void BSP_LCD_SelectLayer(uint32_t LayerIndex) { ActiveLayer = LayerIndex; }
|
||||
|
||||
/**
|
||||
* @brief Sets a LCD Layer visible.
|
||||
* @param LayerIndex: the visible Layer.
|
||||
* @param state: new state of the specified layer.
|
||||
* This parameter can be: ENABLE or DISABLE.
|
||||
*/
|
||||
void BSP_LCD_SetLayerVisible(uint32_t LayerIndex, FunctionalState state) {
|
||||
if (state == ENABLE) {
|
||||
__HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
|
||||
} else {
|
||||
__HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
|
||||
}
|
||||
__HAL_LTDC_RELOAD_CONFIG(&LtdcHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets an LCD Layer visible without reloading.
|
||||
* @param LayerIndex: Visible Layer
|
||||
* @param State: New state of the specified layer
|
||||
* This parameter can be one of the following values:
|
||||
* @arg ENABLE
|
||||
* @arg DISABLE
|
||||
* @retval None
|
||||
*/
|
||||
void BSP_LCD_SetLayerVisible_NoReload(uint32_t LayerIndex,
|
||||
FunctionalState State) {
|
||||
if (State == ENABLE) {
|
||||
__HAL_LTDC_LAYER_ENABLE(&LtdcHandler, LayerIndex);
|
||||
} else {
|
||||
__HAL_LTDC_LAYER_DISABLE(&LtdcHandler, LayerIndex);
|
||||
}
|
||||
/* Do not Sets the Reload */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the Transparency.
|
||||
* @param LayerIndex: the Layer foreground or background.
|
||||
* @param Transparency: the Transparency,
|
||||
* This parameter must range from 0x00 to 0xFF.
|
||||
*/
|
||||
void BSP_LCD_SetTransparency(uint32_t LayerIndex, uint8_t Transparency) {
|
||||
HAL_LTDC_SetAlpha(&LtdcHandler, Transparency, LayerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the transparency without reloading.
|
||||
* @param LayerIndex: Layer foreground or background.
|
||||
* @param Transparency: Transparency
|
||||
* This parameter must be a number between Min_Data = 0x00 and
|
||||
* Max_Data = 0xFF
|
||||
* @retval None
|
||||
*/
|
||||
void BSP_LCD_SetTransparency_NoReload(uint32_t LayerIndex,
|
||||
uint8_t Transparency) {
|
||||
HAL_LTDC_SetAlpha_NoReload(&LtdcHandler, Transparency, LayerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a LCD layer frame buffer address.
|
||||
* @param LayerIndex: specifies the Layer foreground or background
|
||||
* @param Address: new LCD frame buffer value
|
||||
*/
|
||||
void BSP_LCD_SetLayerAddress(uint32_t LayerIndex, uint32_t Address) {
|
||||
HAL_LTDC_SetAddress(&LtdcHandler, Address, LayerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets an LCD layer frame buffer address without reloading.
|
||||
* @param LayerIndex: Layer foreground or background
|
||||
* @param Address: New LCD frame buffer value
|
||||
* @retval None
|
||||
*/
|
||||
void BSP_LCD_SetLayerAddress_NoReload(uint32_t LayerIndex, uint32_t Address) {
|
||||
HAL_LTDC_SetAddress_NoReload(&LtdcHandler, Address, LayerIndex);
|
||||
}
|
||||
|
||||
void BSP_LCD_Init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure = {0};
|
||||
|
||||
/* Enable the LTDC and DMA2D Clock */
|
||||
__HAL_RCC_LTDC_CLK_ENABLE();
|
||||
__HAL_RCC_DMA2D_CLK_ENABLE();
|
||||
|
||||
/* Enable GPIOs clock */
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOB_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOF_CLK_ENABLE();
|
||||
__HAL_RCC_GPIOG_CLK_ENABLE();
|
||||
|
||||
/* GPIOs Configuration */
|
||||
/*
|
||||
+------------------------+-----------------------+----------------------------+
|
||||
+ LCD pins assignment +
|
||||
+------------------------+-----------------------+----------------------------+
|
||||
| LCD_TFT R2 <-> PC.10 | LCD_TFT G2 <-> PA.06 | LCD_TFT B2 <-> PD.06 | |
|
||||
LCD_TFT R3 <-> PB.00 | LCD_TFT G3 <-> PG.10 | LCD_TFT B3 <-> PG.11 |
|
||||
| LCD_TFT R4 <-> PA.11 | LCD_TFT G4 <-> PB.10 | LCD_TFT B4 <-> PG.12 | |
|
||||
LCD_TFT R5 <-> PA.12 | LCD_TFT G5 <-> PB.11 | LCD_TFT B5 <-> PA.03 |
|
||||
| LCD_TFT R6 <-> PB.01 | LCD_TFT G6 <-> PC.07 | LCD_TFT B6 <-> PB.08 | |
|
||||
LCD_TFT R7 <-> PG.06 | LCD_TFT G7 <-> PD.03 | LCD_TFT B7 <-> PB.09 |
|
||||
-------------------------------------------------------------------------------
|
||||
| LCD_TFT HSYNC <-> PC.06 | LCDTFT VSYNC <-> PA.04 |
|
||||
| LCD_TFT CLK <-> PG.07 | LCD_TFT DE <-> PF.10 |
|
||||
-----------------------------------------------------
|
||||
*/
|
||||
|
||||
/* GPIOA configuration */
|
||||
GPIO_InitStructure.Pin =
|
||||
GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_11 | GPIO_PIN_12;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF14_LTDC;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOB configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOC configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOD configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_3 | GPIO_PIN_6;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOF configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_10;
|
||||
HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOG configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_11;
|
||||
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOB configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1;
|
||||
GPIO_InitStructure.Alternate = GPIO_AF9_LTDC;
|
||||
HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
|
||||
|
||||
/* GPIOG configuration */
|
||||
GPIO_InitStructure.Pin = GPIO_PIN_10 | GPIO_PIN_12;
|
||||
HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
|
||||
|
||||
/* On STM32F429I-DISCO, it is not possible to read ILI9341 ID because */
|
||||
/* PIN EXTC is not connected to VDD and then LCD_READ_ID4 is not accessible.
|
||||
*/
|
||||
/* In this case, ReadID function is bypassed.*/
|
||||
/*if(ili9341_drv.ReadID() == ILI9341_ID)*/
|
||||
|
||||
/* LTDC Configuration ----------------------------------------------------*/
|
||||
LtdcHandler.Instance = LTDC;
|
||||
|
||||
/* Timing configuration (Typical configuration from ILI9341 datasheet)
|
||||
HSYNC=10 (9+1)
|
||||
HBP=20 (29-10+1)
|
||||
ActiveW=240 (269-20-10+1)
|
||||
HFP=10 (279-240-20-10+1)
|
||||
|
||||
VSYNC=2 (1+1)
|
||||
VBP=2 (3-2+1)
|
||||
ActiveH=320 (323-2-2+1)
|
||||
VFP=4 (327-320-2-2+1)
|
||||
*/
|
||||
|
||||
/* Configure horizontal synchronization width */
|
||||
LtdcHandler.Init.HorizontalSync = ILI9341_HSYNC;
|
||||
/* Configure vertical synchronization height */
|
||||
LtdcHandler.Init.VerticalSync = ILI9341_VSYNC;
|
||||
/* Configure accumulated horizontal back porch */
|
||||
LtdcHandler.Init.AccumulatedHBP = ILI9341_HBP;
|
||||
/* Configure accumulated vertical back porch */
|
||||
LtdcHandler.Init.AccumulatedVBP = ILI9341_VBP;
|
||||
/* Configure accumulated active width */
|
||||
LtdcHandler.Init.AccumulatedActiveW = 269;
|
||||
/* Configure accumulated active height */
|
||||
LtdcHandler.Init.AccumulatedActiveH = 323;
|
||||
/* Configure total width */
|
||||
LtdcHandler.Init.TotalWidth = 279;
|
||||
/* Configure total height */
|
||||
LtdcHandler.Init.TotalHeigh = 327;
|
||||
|
||||
/* Configure R,G,B component values for LCD background color */
|
||||
LtdcHandler.Init.Backcolor.Red = 0;
|
||||
LtdcHandler.Init.Backcolor.Blue = 0;
|
||||
LtdcHandler.Init.Backcolor.Green = 0;
|
||||
|
||||
/* LCD clock configuration */
|
||||
/* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
|
||||
/* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */
|
||||
/* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 Mhz */
|
||||
/* LTDC clock frequency = PLLLCDCLK / LTDC_PLLSAI_DIVR_8 = 48/4 = 6Mhz */
|
||||
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
|
||||
PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
|
||||
PeriphClkInitStruct.PLLSAI.PLLSAIR = 4;
|
||||
PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;
|
||||
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
|
||||
|
||||
/* Polarity */
|
||||
LtdcHandler.Init.HSPolarity = LTDC_HSPOLARITY_AL;
|
||||
LtdcHandler.Init.VSPolarity = LTDC_VSPOLARITY_AL;
|
||||
LtdcHandler.Init.DEPolarity = LTDC_DEPOLARITY_AL;
|
||||
LtdcHandler.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
|
||||
|
||||
HAL_LTDC_Init(&LtdcHandler);
|
||||
|
||||
/* Initialize the LCD Layers */
|
||||
BSP_LCD_LayerDefaultInit(1, FRAME_BUFFER_ADDR);
|
||||
|
||||
memset((void *)FRAME_BUFFER_ADDR, 0, FRAME_BUFFER_SIZE);
|
||||
}
|
@ -0,0 +1,512 @@
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include TREZOR_BOARD
|
||||
#include "ili9341_spi.h"
|
||||
#include STM32_HAL_H
|
||||
|
||||
/**
|
||||
* @brief ILI9341 chip IDs
|
||||
*/
|
||||
#define ILI9341_ID 0x9341
|
||||
|
||||
/**
|
||||
* @brief ILI9341 Size
|
||||
*/
|
||||
#define ILI9341_LCD_PIXEL_WIDTH ((uint16_t)240)
|
||||
#define ILI9341_LCD_PIXEL_HEIGHT ((uint16_t)320)
|
||||
|
||||
/**
|
||||
* @brief ILI9341 Timing
|
||||
*/
|
||||
/* Timing configuration (Typical configuration from ILI9341 datasheet)
|
||||
HSYNC=10 (9+1)
|
||||
HBP=20 (29-10+1)
|
||||
ActiveW=240 (269-20-10+1)
|
||||
HFP=10 (279-240-20-10+1)
|
||||
|
||||
VSYNC=2 (1+1)
|
||||
VBP=2 (3-2+1)
|
||||
ActiveH=320 (323-2-2+1)
|
||||
VFP=4 (327-320-2-2+1)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief ILI9341 Registers
|
||||
*/
|
||||
|
||||
/* Level 1 Commands */
|
||||
#define LCD_SWRESET 0x01 /* Software Reset */
|
||||
#define LCD_READ_DISPLAY_ID 0x04 /* Read display identification information */
|
||||
#define LCD_RDDST 0x09 /* Read Display Status */
|
||||
#define LCD_RDDPM 0x0A /* Read Display Power Mode */
|
||||
#define LCD_RDDMADCTL 0x0B /* Read Display MADCTL */
|
||||
#define LCD_RDDCOLMOD 0x0C /* Read Display Pixel Format */
|
||||
#define LCD_RDDIM 0x0D /* Read Display Image Format */
|
||||
#define LCD_RDDSM 0x0E /* Read Display Signal Mode */
|
||||
#define LCD_RDDSDR 0x0F /* Read Display Self-Diagnostic Result */
|
||||
#define LCD_SPLIN 0x10 /* Enter Sleep Mode */
|
||||
#define LCD_SLEEP_OUT 0x11 /* Sleep out register */
|
||||
#define LCD_PTLON 0x12 /* Partial Mode ON */
|
||||
#define LCD_NORMAL_MODE_ON 0x13 /* Normal Display Mode ON */
|
||||
#define LCD_DINVOFF 0x20 /* Display Inversion OFF */
|
||||
#define LCD_DINVON 0x21 /* Display Inversion ON */
|
||||
#define LCD_GAMMA 0x26 /* Gamma register */
|
||||
#define LCD_DISPLAY_OFF 0x28 /* Display off register */
|
||||
#define LCD_DISPLAY_ON 0x29 /* Display on register */
|
||||
#define LCD_COLUMN_ADDR 0x2A /* Colomn address register */
|
||||
#define LCD_PAGE_ADDR 0x2B /* Page address register */
|
||||
#define LCD_GRAM 0x2C /* GRAM register */
|
||||
#define LCD_RGBSET 0x2D /* Color SET */
|
||||
#define LCD_RAMRD 0x2E /* Memory Read */
|
||||
#define LCD_PLTAR 0x30 /* Partial Area */
|
||||
#define LCD_VSCRDEF 0x33 /* Vertical Scrolling Definition */
|
||||
#define LCD_TEOFF 0x34 /* Tearing Effect Line OFF */
|
||||
#define LCD_TEON 0x35 /* Tearing Effect Line ON */
|
||||
#define LCD_MAC 0x36 /* Memory Access Control register*/
|
||||
#define LCD_VSCRSADD 0x37 /* Vertical Scrolling Start Address */
|
||||
#define LCD_IDMOFF 0x38 /* Idle Mode OFF */
|
||||
#define LCD_IDMON 0x39 /* Idle Mode ON */
|
||||
#define LCD_PIXEL_FORMAT 0x3A /* Pixel Format register */
|
||||
#define LCD_WRITE_MEM_CONTINUE 0x3C /* Write Memory Continue */
|
||||
#define LCD_READ_MEM_CONTINUE 0x3E /* Read Memory Continue */
|
||||
#define LCD_SET_TEAR_SCANLINE 0x44 /* Set Tear Scanline */
|
||||
#define LCD_GET_SCANLINE 0x45 /* Get Scanline */
|
||||
#define LCD_WDB 0x51 /* Write Brightness Display register */
|
||||
#define LCD_RDDISBV 0x52 /* Read Display Brightness */
|
||||
#define LCD_WCD 0x53 /* Write Control Display register*/
|
||||
#define LCD_RDCTRLD 0x54 /* Read CTRL Display */
|
||||
#define LCD_WRCABC 0x55 /* Write Content Adaptive Brightness Control */
|
||||
#define LCD_RDCABC 0x56 /* Read Content Adaptive Brightness Control */
|
||||
#define LCD_WRITE_CABC 0x5E /* Write CABC Minimum Brightness */
|
||||
#define LCD_READ_CABC 0x5F /* Read CABC Minimum Brightness */
|
||||
#define LCD_READ_ID1 0xDA /* Read ID1 */
|
||||
#define LCD_READ_ID2 0xDB /* Read ID2 */
|
||||
#define LCD_READ_ID3 0xDC /* Read ID3 */
|
||||
|
||||
/* Level 2 Commands */
|
||||
#define LCD_RGB_INTERFACE 0xB0 /* RGB Interface Signal Control */
|
||||
#define LCD_FRMCTR1 0xB1 /* Frame Rate Control (In Normal Mode) */
|
||||
#define LCD_FRMCTR2 0xB2 /* Frame Rate Control (In Idle Mode) */
|
||||
#define LCD_FRMCTR3 0xB3 /* Frame Rate Control (In Partial Mode) */
|
||||
#define LCD_INVTR 0xB4 /* Display Inversion Control */
|
||||
#define LCD_BPC 0xB5 /* Blanking Porch Control register */
|
||||
#define LCD_DFC 0xB6 /* Display Function Control register */
|
||||
#define LCD_ETMOD 0xB7 /* Entry Mode Set */
|
||||
#define LCD_BACKLIGHT1 0xB8 /* Backlight Control 1 */
|
||||
#define LCD_BACKLIGHT2 0xB9 /* Backlight Control 2 */
|
||||
#define LCD_BACKLIGHT3 0xBA /* Backlight Control 3 */
|
||||
#define LCD_BACKLIGHT4 0xBB /* Backlight Control 4 */
|
||||
#define LCD_BACKLIGHT5 0xBC /* Backlight Control 5 */
|
||||
#define LCD_BACKLIGHT7 0xBE /* Backlight Control 7 */
|
||||
#define LCD_BACKLIGHT8 0xBF /* Backlight Control 8 */
|
||||
#define LCD_POWER1 0xC0 /* Power Control 1 register */
|
||||
#define LCD_POWER2 0xC1 /* Power Control 2 register */
|
||||
#define LCD_VCOM1 0xC5 /* VCOM Control 1 register */
|
||||
#define LCD_VCOM2 0xC7 /* VCOM Control 2 register */
|
||||
#define LCD_NVMWR 0xD0 /* NV Memory Write */
|
||||
#define LCD_NVMPKEY 0xD1 /* NV Memory Protection Key */
|
||||
#define LCD_RDNVM 0xD2 /* NV Memory Status Read */
|
||||
#define LCD_READ_ID4 0xD3 /* Read ID4 */
|
||||
#define LCD_PGAMMA 0xE0 /* Positive Gamma Correction register */
|
||||
#define LCD_NGAMMA 0xE1 /* Negative Gamma Correction register */
|
||||
#define LCD_DGAMCTRL1 0xE2 /* Digital Gamma Control 1 */
|
||||
#define LCD_DGAMCTRL2 0xE3 /* Digital Gamma Control 2 */
|
||||
#define LCD_INTERFACE 0xF6 /* Interface control register */
|
||||
|
||||
/* Extend register commands */
|
||||
#define LCD_POWERA 0xCB /* Power control A register */
|
||||
#define LCD_POWERB 0xCF /* Power control B register */
|
||||
#define LCD_DTCA 0xE8 /* Driver timing control A */
|
||||
#define LCD_DTCB 0xEA /* Driver timing control B */
|
||||
#define LCD_POWER_SEQ 0xED /* Power on sequence register */
|
||||
#define LCD_3GAMMA_EN 0xF2 /* 3 Gamma enable register */
|
||||
#define LCD_PRC 0xF7 /* Pump ratio control register */
|
||||
|
||||
/* Size of read registers */
|
||||
#define LCD_READ_ID4_SIZE 3 /* Size of Read ID4 */
|
||||
|
||||
/*############################### SPIx #######################################*/
|
||||
#define DISCOVERY_SPIx SPI5
|
||||
#define DISCOVERY_SPIx_CLK_ENABLE() __HAL_RCC_SPI5_CLK_ENABLE()
|
||||
#define DISCOVERY_SPIx_GPIO_PORT GPIOF /* GPIOF */
|
||||
#define DISCOVERY_SPIx_AF GPIO_AF5_SPI5
|
||||
#define DISCOVERY_SPIx_GPIO_CLK_ENABLE() __HAL_RCC_GPIOF_CLK_ENABLE()
|
||||
#define DISCOVERY_SPIx_GPIO_CLK_DISABLE() __HAL_RCC_GPIOF_CLK_DISABLE()
|
||||
#define DISCOVERY_SPIx_SCK_PIN GPIO_PIN_7 /* PF.07 */
|
||||
#define DISCOVERY_SPIx_MISO_PIN GPIO_PIN_8 /* PF.08 */
|
||||
#define DISCOVERY_SPIx_MOSI_PIN GPIO_PIN_9 /* PF.09 */
|
||||
/* Maximum Timeout values for flags waiting loops. These timeouts are not based
|
||||
on accurate values, they just guarantee that the application will not remain
|
||||
stuck if the SPI communication is corrupted.
|
||||
You may modify these timeout values depending on CPU frequency and
|
||||
application conditions (interrupts routines ...). */
|
||||
#define SPIx_TIMEOUT_MAX ((uint32_t)0x1000)
|
||||
|
||||
/*################################ LCD #######################################*/
|
||||
/* Chip Select macro definition */
|
||||
#define LCD_CS_LOW() \
|
||||
HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_RESET)
|
||||
#define LCD_CS_HIGH() \
|
||||
HAL_GPIO_WritePin(LCD_NCS_GPIO_PORT, LCD_NCS_PIN, GPIO_PIN_SET)
|
||||
|
||||
/* Set WRX High to send data */
|
||||
#define LCD_WRX_LOW() \
|
||||
HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_RESET)
|
||||
#define LCD_WRX_HIGH() \
|
||||
HAL_GPIO_WritePin(LCD_WRX_GPIO_PORT, LCD_WRX_PIN, GPIO_PIN_SET)
|
||||
|
||||
/* Set WRX High to send data */
|
||||
#define LCD_RDX_LOW() \
|
||||
HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_RESET)
|
||||
#define LCD_RDX_HIGH() \
|
||||
HAL_GPIO_WritePin(LCD_RDX_GPIO_PORT, LCD_RDX_PIN, GPIO_PIN_SET)
|
||||
|
||||
/**
|
||||
* @brief LCD Control pin
|
||||
*/
|
||||
#define LCD_NCS_PIN GPIO_PIN_2
|
||||
#define LCD_NCS_GPIO_PORT GPIOC
|
||||
#define LCD_NCS_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
|
||||
#define LCD_NCS_GPIO_CLK_DISABLE() __HAL_RCC_GPIOC_CLK_DISABLE()
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/**
|
||||
* @brief LCD Command/data pin
|
||||
*/
|
||||
#define LCD_WRX_PIN GPIO_PIN_13
|
||||
#define LCD_WRX_GPIO_PORT GPIOD
|
||||
#define LCD_WRX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
|
||||
#define LCD_WRX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
|
||||
|
||||
#define LCD_RDX_PIN GPIO_PIN_12
|
||||
#define LCD_RDX_GPIO_PORT GPIOD
|
||||
#define LCD_RDX_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
|
||||
#define LCD_RDX_GPIO_CLK_DISABLE() __HAL_RCC_GPIOD_CLK_DISABLE()
|
||||
|
||||
static SPI_HandleTypeDef SpiHandle;
|
||||
uint32_t SpixTimeout =
|
||||
SPIx_TIMEOUT_MAX; /*<! Value of Timeout when SPI communication fails */
|
||||
|
||||
/* SPIx bus function */
|
||||
static void SPIx_Init(void);
|
||||
static void ili9341_Write(uint16_t Value);
|
||||
static uint32_t ili9341_Read(uint8_t ReadSize);
|
||||
static void ili9341_Error(void);
|
||||
|
||||
/**
|
||||
* @brief SPIx Bus initialization
|
||||
*/
|
||||
static void SPIx_Init(void) {
|
||||
if (HAL_SPI_GetState(&SpiHandle) == HAL_SPI_STATE_RESET) {
|
||||
/* SPI configuration -----------------------------------------------------*/
|
||||
SpiHandle.Instance = DISCOVERY_SPIx;
|
||||
/* SPI baudrate is set to 5.6 MHz (PCLK2/SPI_BaudRatePrescaler = 90/16
|
||||
= 5.625 MHz) to verify these constraints:
|
||||
- ILI9341 LCD SPI interface max baudrate is 10MHz for write and 6.66MHz
|
||||
for read
|
||||
- l3gd20 SPI interface max baudrate is 10MHz for write/read
|
||||
- PCLK2 frequency is set to 90 MHz
|
||||
*/
|
||||
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
|
||||
|
||||
/* On STM32F429I-Discovery, LCD ID cannot be read then keep a common
|
||||
* configuration */
|
||||
/* for LCD and GYRO (SPI_DIRECTION_2LINES) */
|
||||
/* Note: To read a register a LCD, SPI_DIRECTION_1LINE should be set */
|
||||
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
|
||||
SpiHandle.Init.CRCPolynomial = 7;
|
||||
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
SpiHandle.Init.NSS = SPI_NSS_SOFT;
|
||||
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLED;
|
||||
SpiHandle.Init.Mode = SPI_MODE_MASTER;
|
||||
|
||||
HAL_SPI_Init(&SpiHandle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SPIx error treatment function.
|
||||
*/
|
||||
static void ili9341_Error(void) {
|
||||
/* De-initialize the SPI communication BUS */
|
||||
HAL_SPI_DeInit(&SpiHandle);
|
||||
|
||||
/* Re- Initialize the SPI communication BUS */
|
||||
SPIx_Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads 4 bytes from device.
|
||||
* @param ReadSize: Number of bytes to read (max 4 bytes)
|
||||
* @retval Value read on the SPI
|
||||
*/
|
||||
static uint32_t ili9341_Read(uint8_t ReadSize) {
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
uint32_t readvalue;
|
||||
|
||||
status =
|
||||
HAL_SPI_Receive(&SpiHandle, (uint8_t*)&readvalue, ReadSize, SpixTimeout);
|
||||
|
||||
/* Check the communication status */
|
||||
if (status != HAL_OK) {
|
||||
/* Re-Initialize the BUS */
|
||||
ili9341_Error();
|
||||
}
|
||||
|
||||
return readvalue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes a byte to device.
|
||||
* @param Value: value to be written
|
||||
*/
|
||||
static void ili9341_Write(uint16_t Value) {
|
||||
HAL_StatusTypeDef status = HAL_OK;
|
||||
|
||||
status = HAL_SPI_Transmit(&SpiHandle, (uint8_t*)&Value, 1, SpixTimeout);
|
||||
|
||||
/* Check the communication status */
|
||||
if (status != HAL_OK) {
|
||||
/* Re-Initialize the BUS */
|
||||
ili9341_Error();
|
||||
}
|
||||
}
|
||||
|
||||
void ili9341_spi_init(void) {
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
/* Configure NCS in Output Push-Pull mode */
|
||||
LCD_WRX_GPIO_CLK_ENABLE();
|
||||
GPIO_InitStructure.Pin = LCD_WRX_PIN;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
HAL_GPIO_Init(LCD_WRX_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
LCD_RDX_GPIO_CLK_ENABLE();
|
||||
GPIO_InitStructure.Pin = LCD_RDX_PIN;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
HAL_GPIO_Init(LCD_RDX_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/* Configure the LCD Control pins ----------------------------------------*/
|
||||
LCD_NCS_GPIO_CLK_ENABLE();
|
||||
|
||||
/* Configure NCS in Output Push-Pull mode */
|
||||
GPIO_InitStructure.Pin = LCD_NCS_PIN;
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
|
||||
HAL_GPIO_Init(LCD_NCS_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
/* Set or Reset the control line */
|
||||
LCD_CS_LOW();
|
||||
LCD_CS_HIGH();
|
||||
|
||||
/* Enable SPIx clock */
|
||||
DISCOVERY_SPIx_CLK_ENABLE();
|
||||
|
||||
/* Enable DISCOVERY_SPI GPIO clock */
|
||||
DISCOVERY_SPIx_GPIO_CLK_ENABLE();
|
||||
|
||||
/* configure SPI SCK, MOSI and MISO */
|
||||
GPIO_InitStructure.Pin = (DISCOVERY_SPIx_SCK_PIN | DISCOVERY_SPIx_MOSI_PIN |
|
||||
DISCOVERY_SPIx_MISO_PIN);
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_MEDIUM;
|
||||
GPIO_InitStructure.Alternate = DISCOVERY_SPIx_AF;
|
||||
HAL_GPIO_Init(DISCOVERY_SPIx_GPIO_PORT, &GPIO_InitStructure);
|
||||
|
||||
SPIx_Init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes register value.
|
||||
*/
|
||||
void ili9341_WriteData(uint16_t RegValue) {
|
||||
/* Set WRX to send data */
|
||||
LCD_WRX_HIGH();
|
||||
|
||||
/* Reset LCD control line(/CS) and Send data */
|
||||
LCD_CS_LOW();
|
||||
ili9341_Write(RegValue);
|
||||
|
||||
/* Deselect: Chip Select high */
|
||||
LCD_CS_HIGH();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes register address.
|
||||
*/
|
||||
void ili9341_WriteReg(uint8_t Reg) {
|
||||
/* Reset WRX to send command */
|
||||
LCD_WRX_LOW();
|
||||
|
||||
/* Reset LCD control line(/CS) and Send command */
|
||||
LCD_CS_LOW();
|
||||
ili9341_Write(Reg);
|
||||
|
||||
/* Deselect: Chip Select high */
|
||||
LCD_CS_HIGH();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads register value.
|
||||
* @param RegValue Address of the register to read
|
||||
* @param ReadSize Number of bytes to read
|
||||
* @retval Content of the register value
|
||||
*/
|
||||
uint32_t ili9341_ReadData(uint16_t RegValue, uint8_t ReadSize) {
|
||||
uint32_t readvalue = 0;
|
||||
|
||||
/* Select: Chip Select low */
|
||||
LCD_CS_LOW();
|
||||
|
||||
/* Reset WRX to send command */
|
||||
LCD_WRX_LOW();
|
||||
|
||||
ili9341_Write(RegValue);
|
||||
|
||||
readvalue = ili9341_Read(ReadSize);
|
||||
|
||||
/* Set WRX to send data */
|
||||
LCD_WRX_HIGH();
|
||||
|
||||
/* Deselect: Chip Select high */
|
||||
LCD_CS_HIGH();
|
||||
|
||||
return readvalue;
|
||||
}
|
||||
|
||||
void ili9341_init(void) {
|
||||
/* Initialize ILI9341 low level bus layer ----------------------------------*/
|
||||
ili9341_spi_init();
|
||||
|
||||
ili9341_WriteReg(LCD_DISPLAY_OFF);
|
||||
|
||||
/* Configure LCD */
|
||||
ili9341_WriteReg(0xCA);
|
||||
ili9341_WriteData(0xC3);
|
||||
ili9341_WriteData(0x08);
|
||||
ili9341_WriteData(0x50);
|
||||
ili9341_WriteReg(LCD_POWERB);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0xC1);
|
||||
ili9341_WriteData(0x30);
|
||||
ili9341_WriteReg(LCD_POWER_SEQ);
|
||||
ili9341_WriteData(0x64);
|
||||
ili9341_WriteData(0x03);
|
||||
ili9341_WriteData(0x12);
|
||||
ili9341_WriteData(0x81);
|
||||
ili9341_WriteReg(LCD_DTCA);
|
||||
ili9341_WriteData(0x85);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x78);
|
||||
ili9341_WriteReg(LCD_POWERA);
|
||||
ili9341_WriteData(0x39);
|
||||
ili9341_WriteData(0x2C);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x34);
|
||||
ili9341_WriteData(0x02);
|
||||
ili9341_WriteReg(LCD_PRC);
|
||||
ili9341_WriteData(0x20);
|
||||
ili9341_WriteReg(LCD_DTCB);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteReg(LCD_FRMCTR1);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x1B);
|
||||
ili9341_WriteReg(LCD_DFC);
|
||||
ili9341_WriteData(0x0A);
|
||||
ili9341_WriteData(0xA2);
|
||||
ili9341_WriteReg(LCD_POWER1);
|
||||
ili9341_WriteData(0x10);
|
||||
ili9341_WriteReg(LCD_POWER2);
|
||||
ili9341_WriteData(0x10);
|
||||
ili9341_WriteReg(LCD_VCOM1);
|
||||
ili9341_WriteData(0x45);
|
||||
ili9341_WriteData(0x15);
|
||||
ili9341_WriteReg(LCD_VCOM2);
|
||||
ili9341_WriteData(0x90);
|
||||
ili9341_WriteReg(LCD_MAC);
|
||||
ili9341_WriteData(0xC8);
|
||||
ili9341_WriteReg(LCD_3GAMMA_EN);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteReg(LCD_RGB_INTERFACE);
|
||||
ili9341_WriteData(0xC2);
|
||||
ili9341_WriteReg(LCD_DFC);
|
||||
ili9341_WriteData(0x0A);
|
||||
ili9341_WriteData(0xA7);
|
||||
ili9341_WriteData(0x27);
|
||||
ili9341_WriteData(0x04);
|
||||
|
||||
/* Colomn address set */
|
||||
ili9341_WriteReg(LCD_COLUMN_ADDR);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0xEF);
|
||||
/* Page address set */
|
||||
ili9341_WriteReg(LCD_PAGE_ADDR);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x01);
|
||||
ili9341_WriteData(0x3F);
|
||||
ili9341_WriteReg(LCD_INTERFACE);
|
||||
ili9341_WriteData(0x01);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x06);
|
||||
|
||||
ili9341_WriteReg(LCD_GRAM);
|
||||
HAL_Delay(200);
|
||||
|
||||
ili9341_WriteReg(LCD_GAMMA);
|
||||
ili9341_WriteData(0x01);
|
||||
|
||||
ili9341_WriteReg(LCD_PGAMMA);
|
||||
ili9341_WriteData(0x0F);
|
||||
ili9341_WriteData(0x29);
|
||||
ili9341_WriteData(0x24);
|
||||
ili9341_WriteData(0x0C);
|
||||
ili9341_WriteData(0x0E);
|
||||
ili9341_WriteData(0x09);
|
||||
ili9341_WriteData(0x4E);
|
||||
ili9341_WriteData(0x78);
|
||||
ili9341_WriteData(0x3C);
|
||||
ili9341_WriteData(0x09);
|
||||
ili9341_WriteData(0x13);
|
||||
ili9341_WriteData(0x05);
|
||||
ili9341_WriteData(0x17);
|
||||
ili9341_WriteData(0x11);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteReg(LCD_NGAMMA);
|
||||
ili9341_WriteData(0x00);
|
||||
ili9341_WriteData(0x16);
|
||||
ili9341_WriteData(0x1B);
|
||||
ili9341_WriteData(0x04);
|
||||
ili9341_WriteData(0x11);
|
||||
ili9341_WriteData(0x07);
|
||||
ili9341_WriteData(0x31);
|
||||
ili9341_WriteData(0x33);
|
||||
ili9341_WriteData(0x42);
|
||||
ili9341_WriteData(0x05);
|
||||
ili9341_WriteData(0x0C);
|
||||
ili9341_WriteData(0x0A);
|
||||
ili9341_WriteData(0x28);
|
||||
ili9341_WriteData(0x2F);
|
||||
ili9341_WriteData(0x0F);
|
||||
|
||||
ili9341_WriteReg(LCD_SLEEP_OUT);
|
||||
HAL_Delay(200);
|
||||
ili9341_WriteReg(LCD_DISPLAY_ON);
|
||||
/* GRAM start writing */
|
||||
ili9341_WriteReg(LCD_GRAM);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#ifndef _ILI9341_SPI_H
|
||||
#define _ILI9341_SPI_H
|
||||
|
||||
#define ILI9341_HSYNC ((uint32_t)9) /* Horizontal synchronization */
|
||||
#define ILI9341_HBP ((uint32_t)29) /* Horizontal back porch */
|
||||
#define ILI9341_HFP ((uint32_t)2) /* Horizontal front porch */
|
||||
#define ILI9341_VSYNC ((uint32_t)1) /* Vertical synchronization */
|
||||
#define ILI9341_VBP ((uint32_t)3) /* Vertical back porch */
|
||||
#define ILI9341_VFP ((uint32_t)2) /* Vertical front porch */
|
||||
|
||||
void ili9341_init(void);
|
||||
|
||||
#endif //_ILI9341_SPI_H
|
@ -0,0 +1,379 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "xdisplay.h"
|
||||
|
||||
#ifdef USE_CONSUMPTION_MASK
|
||||
#include "consumption_mask.h"
|
||||
#endif
|
||||
|
||||
#if (DISPLAY_RESX != 128) || (DISPLAY_RESY != 64)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// This file implements display driver for monochromatic display V-2864KSWEG01
|
||||
// with 128x64 resolution connected to CPU via SPI interface.
|
||||
//
|
||||
// This type of display is used with T3T1 model (Trezor TS3)
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// SPI driver instance
|
||||
SPI_HandleTypeDef spi;
|
||||
// Frame buffer (8-bit Mono)
|
||||
uint8_t framebuf[DISPLAY_RESX * DISPLAY_RESY];
|
||||
// Current display orientation (0 or 180)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
// Display controller registers
|
||||
#define OLED_SETCONTRAST 0x81
|
||||
#define OLED_DISPLAYALLON_RESUME 0xA4
|
||||
#define OLED_DISPLAYALLON 0xA5
|
||||
#define OLED_NORMALDISPLAY 0xA6
|
||||
#define OLED_INVERTDISPLAY 0xA7
|
||||
#define OLED_DISPLAYOFF 0xAE
|
||||
#define OLED_DISPLAYON 0xAF
|
||||
#define OLED_SETDISPLAYOFFSET 0xD3
|
||||
#define OLED_SETCOMPINS 0xDA
|
||||
#define OLED_SETVCOMDETECT 0xDB
|
||||
#define OLED_SETDISPLAYCLOCKDIV 0xD5
|
||||
#define OLED_SETPRECHARGE 0xD9
|
||||
#define OLED_SETMULTIPLEX 0xA8
|
||||
#define OLED_SETLOWCOLUMN 0x00
|
||||
#define OLED_SETHIGHCOLUMN 0x10
|
||||
#define OLED_SETSTARTLINE 0x40
|
||||
#define OLED_MEMORYMODE 0x20
|
||||
#define OLED_COMSCANINC 0xC0
|
||||
#define OLED_COMSCANDEC 0xC8
|
||||
#define OLED_SEGREMAP 0xA0
|
||||
#define OLED_CHARGEPUMP 0x8D
|
||||
|
||||
// Display controller initialization sequence
|
||||
static const uint8_t vg_2864ksweg01_init_seq[] = {OLED_DISPLAYOFF,
|
||||
OLED_SETDISPLAYCLOCKDIV,
|
||||
0x80,
|
||||
OLED_SETMULTIPLEX,
|
||||
0x3F, // 128x64
|
||||
OLED_SETDISPLAYOFFSET,
|
||||
0x00,
|
||||
OLED_SETSTARTLINE | 0x00,
|
||||
OLED_CHARGEPUMP,
|
||||
0x14,
|
||||
OLED_MEMORYMODE,
|
||||
0x00,
|
||||
OLED_SEGREMAP | 0x01,
|
||||
OLED_COMSCANDEC,
|
||||
OLED_SETCOMPINS,
|
||||
0x12, // 128x64
|
||||
OLED_SETCONTRAST,
|
||||
0xCF,
|
||||
OLED_SETPRECHARGE,
|
||||
0xF1,
|
||||
OLED_SETVCOMDETECT,
|
||||
0x40,
|
||||
OLED_DISPLAYALLON_RESUME,
|
||||
OLED_NORMALDISPLAY,
|
||||
OLED_DISPLAYON};
|
||||
|
||||
// Configures SPI driver/controller
|
||||
static bool display_init_spi(display_driver_t *drv) {
|
||||
drv->spi.Instance = OLED_SPI;
|
||||
drv->spi.State = HAL_SPI_STATE_RESET;
|
||||
drv->spi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
|
||||
drv->spi.Init.Direction = SPI_DIRECTION_2LINES;
|
||||
drv->spi.Init.CLKPhase = SPI_PHASE_1EDGE;
|
||||
drv->spi.Init.CLKPolarity = SPI_POLARITY_LOW;
|
||||
drv->spi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
||||
drv->spi.Init.CRCPolynomial = 7;
|
||||
drv->spi.Init.DataSize = SPI_DATASIZE_8BIT;
|
||||
drv->spi.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
||||
drv->spi.Init.NSS = SPI_NSS_HARD_OUTPUT;
|
||||
drv->spi.Init.TIMode = SPI_TIMODE_DISABLE;
|
||||
drv->spi.Init.Mode = SPI_MODE_MASTER;
|
||||
|
||||
return (HAL_OK == HAL_SPI_Init(&drv->spi)) ? true : false;
|
||||
}
|
||||
|
||||
// Sends specified number of bytes to the display via SPI interface
|
||||
static void display_send_bytes(display_driver_t *drv, const uint8_t *data,
|
||||
size_t len) {
|
||||
volatile int32_t timeout = 1000;
|
||||
for (int i = 0; i < timeout; i++)
|
||||
;
|
||||
|
||||
if (HAL_OK != HAL_SPI_Transmit(&drv->spi, (uint8_t *)data, len, 1000)) {
|
||||
// TODO: error
|
||||
return;
|
||||
}
|
||||
while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) {
|
||||
}
|
||||
}
|
||||
|
||||
#define COLLECT_ROW_BYTE(src) \
|
||||
(0 | (*(src + (0 * DISPLAY_RESX)) >= 128 ? 128 : 0) | \
|
||||
(*(src + (1 * DISPLAY_RESX)) >= 128 ? 64 : 0) | \
|
||||
(*(src + (2 * DISPLAY_RESX)) >= 128 ? 32 : 0) | \
|
||||
(*(src + (3 * DISPLAY_RESX)) >= 128 ? 16 : 0) | \
|
||||
(*(src + (4 * DISPLAY_RESX)) >= 128 ? 8 : 0) | \
|
||||
(*(src + (5 * DISPLAY_RESX)) >= 128 ? 4 : 0) | \
|
||||
(*(src + (6 * DISPLAY_RESX)) >= 128 ? 2 : 0) | \
|
||||
(*(src + (7 * DISPLAY_RESX)) >= 128 ? 1 : 0))
|
||||
|
||||
#define COLLECT_ROW_BYTE_REV(src) \
|
||||
(0 | (*(src + (0 * DISPLAY_RESX)) >= 128 ? 1 : 0) | \
|
||||
(*(src + (1 * DISPLAY_RESX)) >= 128 ? 2 : 0) | \
|
||||
(*(src + (2 * DISPLAY_RESX)) >= 128 ? 4 : 0) | \
|
||||
(*(src + (3 * DISPLAY_RESX)) >= 128 ? 8 : 0) | \
|
||||
(*(src + (4 * DISPLAY_RESX)) >= 128 ? 16 : 0) | \
|
||||
(*(src + (5 * DISPLAY_RESX)) >= 128 ? 32 : 0) | \
|
||||
(*(src + (6 * DISPLAY_RESX)) >= 128 ? 64 : 0) | \
|
||||
(*(src + (7 * DISPLAY_RESX)) >= 128 ? 128 : 0))
|
||||
|
||||
// Copies the framebuffer to the display via SPI interface
|
||||
static void display_sync_with_fb(display_driver_t *drv) {
|
||||
static const uint8_t cursor_set_seq[3] = {OLED_SETLOWCOLUMN | 0x00,
|
||||
OLED_SETHIGHCOLUMN | 0x00,
|
||||
OLED_SETSTARTLINE | 0x00};
|
||||
|
||||
// SPI select
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
// Set the cursor to the screen top-left corner
|
||||
display_send_bytes(drv, &cursor_set_seq[0], sizeof(cursor_set_seq));
|
||||
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
// Set to DATA
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_SET);
|
||||
// SPI select
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
|
||||
// Send whole framebuffer to the display
|
||||
|
||||
if (drv->orientation_angle == 0) {
|
||||
for (int y = DISPLAY_RESY / 8 - 1; y >= 0; y--) {
|
||||
uint8_t buff[DISPLAY_RESX];
|
||||
uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8];
|
||||
|
||||
for (int x = DISPLAY_RESX - 1; x >= 0; x--) {
|
||||
buff[x] = COLLECT_ROW_BYTE(src);
|
||||
src++;
|
||||
}
|
||||
|
||||
if (HAL_OK != HAL_SPI_Transmit(&drv->spi, &buff[0], sizeof(buff), 1000)) {
|
||||
// TODO: error
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < DISPLAY_RESY / 8; y++) {
|
||||
uint8_t buff[DISPLAY_RESX];
|
||||
uint8_t *src = &drv->framebuf[y * DISPLAY_RESX * 8];
|
||||
|
||||
for (int x = 0; x < DISPLAY_RESX; x++) {
|
||||
buff[x] = COLLECT_ROW_BYTE_REV(src);
|
||||
src++;
|
||||
}
|
||||
|
||||
if (HAL_OK != HAL_SPI_Transmit(&drv->spi, &buff[0], sizeof(buff), 1000)) {
|
||||
// TODO: error
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (HAL_SPI_STATE_READY != HAL_SPI_GetState(&drv->spi)) {
|
||||
}
|
||||
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
// Set to CMD
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
|
||||
}
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
drv->backlight_level = 255;
|
||||
|
||||
OLED_DC_CLK_ENA();
|
||||
OLED_CS_CLK_ENA();
|
||||
OLED_RST_CLK_ENA();
|
||||
OLED_SPI_SCK_CLK_ENA();
|
||||
OLED_SPI_MOSI_CLK_ENA();
|
||||
OLED_SPI_CLK_ENA();
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStructure;
|
||||
|
||||
// Set GPIO for OLED display
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = 0;
|
||||
GPIO_InitStructure.Pin = OLED_CS_PIN;
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(OLED_CS_PORT, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = OLED_DC_PIN;
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(OLED_DC_PORT, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = OLED_RST_PIN;
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
|
||||
HAL_GPIO_Init(OLED_RST_PORT, &GPIO_InitStructure);
|
||||
|
||||
// Enable SPI 1 for OLED display
|
||||
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStructure.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
GPIO_InitStructure.Alternate = OLED_SPI_AF;
|
||||
GPIO_InitStructure.Pin = OLED_SPI_SCK_PIN;
|
||||
HAL_GPIO_Init(OLED_SPI_SCK_PORT, &GPIO_InitStructure);
|
||||
GPIO_InitStructure.Pin = OLED_SPI_MOSI_PIN;
|
||||
HAL_GPIO_Init(OLED_SPI_MOSI_PORT, &GPIO_InitStructure);
|
||||
|
||||
// Initialize SPI controller
|
||||
display_init_spi(drv);
|
||||
|
||||
// Set to CMD
|
||||
HAL_GPIO_WritePin(OLED_DC_PORT, OLED_DC_PIN, GPIO_PIN_RESET);
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
|
||||
// Reset the LCD
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
|
||||
HAL_Delay(1);
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);
|
||||
HAL_Delay(1);
|
||||
HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);
|
||||
|
||||
// SPI select
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_RESET);
|
||||
// Send initialization command sequence
|
||||
display_send_bytes(drv, &vg_2864ksweg01_init_seq[0],
|
||||
sizeof(vg_2864ksweg01_init_seq));
|
||||
// SPI deselect
|
||||
HAL_GPIO_WritePin(OLED_CS_PORT, OLED_CS_PIN, GPIO_PIN_SET);
|
||||
|
||||
// Clear display internal framebuffer
|
||||
display_sync_with_fb(drv);
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
memset(drv, 0, sizeof(display_driver_t));
|
||||
drv->backlight_level = 255;
|
||||
|
||||
display_init_spi(drv);
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
/// Not used and intentionally left empty
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
drv->backlight_level = 255;
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (angle != drv->orientation_angle) {
|
||||
if (angle == 0 || angle == 180) {
|
||||
drv->orientation_angle = angle;
|
||||
display_sync_with_fb(drv);
|
||||
}
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
display_fb_info_t display_get_frame_buffer(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
display_fb_info_t fb = {
|
||||
.ptr = &drv->framebuf[0],
|
||||
.stride = DISPLAY_RESX,
|
||||
};
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
void display_refresh(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
#if defined USE_CONSUMPTION_MASK && !defined BOARDLOADER
|
||||
// This is an intentional randomization of the consumption masking algorithm
|
||||
// after every change on the display
|
||||
consumption_mask_randomize();
|
||||
#endif
|
||||
|
||||
// Sends the current frame buffer to the display
|
||||
display_sync_with_fb(drv);
|
||||
}
|
||||
|
||||
void display_set_compatible_settings() {}
|
||||
|
||||
void display_fill(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y];
|
||||
bb_new.dst_stride = DISPLAY_RESX;
|
||||
|
||||
gl_mono8_fill(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_mono1p(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row = &drv->framebuf[DISPLAY_RESX * bb_new.dst_y];
|
||||
bb_new.dst_stride = DISPLAY_RESX;
|
||||
|
||||
gl_mono8_copy_mono1p(&bb_new);
|
||||
}
|
@ -0,0 +1,616 @@
|
||||
/*
|
||||
* 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 STM32_HAL_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "dma2d_bitblt.h"
|
||||
#include "gl_color.h"
|
||||
|
||||
static DMA2D_HandleTypeDef dma2d_handle = {
|
||||
.Instance = (DMA2D_TypeDef*)DMA2D_BASE,
|
||||
};
|
||||
|
||||
bool dma2d_accessible(const void* ptr) {
|
||||
#ifdef STM32F4
|
||||
const void* ccm_start = (const void*)0x10000000;
|
||||
const void* ccm_end = (const void*)0x1000FFFF;
|
||||
return !(ptr >= ccm_start && ptr <= ccm_end);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dma2d_wait(void) {
|
||||
while (HAL_DMA2D_PollForTransfer(&dma2d_handle, 10) != HAL_OK)
|
||||
;
|
||||
}
|
||||
|
||||
void dma2d_rgb565_fill(const gl_bitblt_t* bb) {
|
||||
dma2d_wait();
|
||||
|
||||
if (bb->src_alpha == 255) {
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
|
||||
dma2d_handle.Init.Mode = DMA2D_R2M;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
HAL_DMA2D_Start(&dma2d_handle, gl_color_to_color32(bb->src_fg),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
|
||||
bb->width, bb->height);
|
||||
/*
|
||||
|
||||
MODIFY_REG(dma2d_handle.Instance->CR, DMA2D_CR_MODE, DMA2D_R2M);
|
||||
MODIFY_REG(dma2d_handle.Instance->OPFCCR, DMA2D_OPFCCR_CM,
|
||||
DMA2D_OUTPUT_RGB565); MODIFY_REG(dma2d_handle.Instance->OOR,
|
||||
DMA2D_OOR_LO, bb->dst_stride / sizeof(uint16_t) - bb->width);
|
||||
MODIFY_REG(dma2d_handle.Instance->NLR, (DMA2D_NLR_NL|DMA2D_NLR_PL),
|
||||
(bb->height| (bb->width << 16))); WRITE_REG(dma2d_handle.Instance->OMAR,
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t));
|
||||
WRITE_REG(dma2d_handle.Instance->OCOLR,
|
||||
gl_color_to_color32(bb->src_fg));
|
||||
((dma2d_handle).Instance->CR |= DMA2D_CR_START);
|
||||
*/
|
||||
} else {
|
||||
#ifdef STM32U5
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND_FG;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
|
||||
dma2d_handle.LayerCfg[1].InputOffset = 0;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
|
||||
dma2d_handle.LayerCfg[0].InputOffset =
|
||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||
dma2d_handle.LayerCfg[0].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[0].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
|
||||
|
||||
HAL_DMA2D_BlendingStart(
|
||||
&dma2d_handle, gl_color_to_color32(bb->src_fg),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t), bb->width,
|
||||
bb->height);
|
||||
#else
|
||||
// STM32F4 can not accelerate blending with the fixed color
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
uint8_t alpha = bb->src_alpha;
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color16_blend_a8(
|
||||
bb->src_fg, gl_color16_to_color(dst_ptr[x]), alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void dma2d_config_clut(uint32_t layer, gl_color_t fg, gl_color_t bg) {
|
||||
|
||||
#define LAYER_COUNT 2
|
||||
#define GRADIENT_STEPS 16
|
||||
|
||||
static struct {
|
||||
gl_color32_t gradient[GRADIENT_STEPS];
|
||||
} cache[LAYER_COUNT] = { 0 };
|
||||
|
||||
if (layer >= LAYER_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t c_fg = gl_color_to_color32(fg);
|
||||
uint32_t c_bg = gl_color_to_color32(bg);
|
||||
|
||||
uint32_t* gradient = cache[layer].gradient;
|
||||
|
||||
if (c_bg != gradient[0] || c_fg != gradient[GRADIENT_STEPS - 1]) {
|
||||
for (int step = 0; step < GRADIENT_STEPS; step++) {
|
||||
gradient[step] = gl_color32_blend_a4(fg, bg, step);
|
||||
}
|
||||
|
||||
DMA2D_CLUTCfgTypeDef clut;
|
||||
clut.CLUTColorMode = DMA2D_CCM_ARGB8888;
|
||||
clut.Size = GRADIENT_STEPS - 1;
|
||||
clut.pCLUT = gradient;
|
||||
|
||||
HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut, layer);
|
||||
|
||||
while (HAL_DMA2D_PollForTransfer(&dma2d_handle, 10) != HAL_OK)
|
||||
;
|
||||
}
|
||||
}*/
|
||||
|
||||
static void dma2d_config_clut(uint32_t layer, gl_color_t fg, gl_color_t bg) {
|
||||
#define LAYER_COUNT 2
|
||||
#define GRADIENT_STEPS 16
|
||||
|
||||
static struct {
|
||||
gl_color_t c_fg;
|
||||
gl_color_t c_bg;
|
||||
} cache[LAYER_COUNT] = {0};
|
||||
|
||||
if (layer >= LAYER_COUNT) {
|
||||
return;
|
||||
}
|
||||
|
||||
volatile uint32_t* clut =
|
||||
layer ? dma2d_handle.Instance->FGCLUT : dma2d_handle.Instance->BGCLUT;
|
||||
|
||||
if (fg != cache[layer].c_fg || bg != cache[layer].c_bg) {
|
||||
cache[layer].c_fg = fg;
|
||||
cache[layer].c_bg = bg;
|
||||
|
||||
for (int step = 0; step < GRADIENT_STEPS; step++) {
|
||||
clut[step] = gl_color32_blend_a4(fg, bg, step);
|
||||
}
|
||||
|
||||
DMA2D_CLUTCfgTypeDef clut;
|
||||
clut.CLUTColorMode = DMA2D_CCM_ARGB8888;
|
||||
clut.Size = GRADIENT_STEPS - 1;
|
||||
clut.pCLUT = 0; // ???
|
||||
|
||||
HAL_DMA2D_ConfigCLUT(&dma2d_handle, clut, layer);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma2d_rgb565_copy_mono4_first_col(gl_bitblt_t* bb,
|
||||
const gl_color16_t* gradient) {
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_lum = src_ptr[0] >> 4;
|
||||
dst_ptr[0] = gradient[fg_lum];
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma2d_rgb565_copy_mono4_last_col(gl_bitblt_t* bb,
|
||||
const gl_color16_t* gradient) {
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_lum = src_ptr[0] & 0x0F;
|
||||
dst_ptr[0] = gradient[fg_lum];
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void dma2d_rgb565_copy_mono4(const gl_bitblt_t* params) {
|
||||
const gl_color16_t* src_gradient = NULL;
|
||||
|
||||
gl_bitblt_t bb_copy = *params;
|
||||
gl_bitblt_t* bb = &bb_copy;
|
||||
|
||||
dma2d_wait();
|
||||
|
||||
if (bb->src_x & 1) {
|
||||
// First column of mono4 bitmap is odd
|
||||
// Use the CPU to draw the first column
|
||||
src_gradient = gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
dma2d_rgb565_copy_mono4_first_col(bb, src_gradient);
|
||||
bb->dst_x += 1;
|
||||
bb->src_x += 1;
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
if (bb->width > 0 && bb->width & 1) {
|
||||
// The width is odd
|
||||
// Use the CPU to draw the last column
|
||||
if (src_gradient == NULL) {
|
||||
src_gradient = gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
}
|
||||
dma2d_rgb565_copy_mono4_last_col(bb, src_gradient);
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4;
|
||||
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
dma2d_config_clut(1, bb->src_fg, bb->src_bg);
|
||||
|
||||
HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
|
||||
bb->width, bb->height);
|
||||
}
|
||||
|
||||
void dma2d_rgb565_copy_rgb565(const gl_bitblt_t* bb) {
|
||||
dma2d_wait();
|
||||
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
|
||||
dma2d_handle.LayerCfg[1].InputOffset =
|
||||
bb->src_stride / sizeof(uint16_t) - bb->width;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
HAL_DMA2D_Start(&dma2d_handle,
|
||||
(uint32_t)bb->src_row + bb->src_x * sizeof(uint16_t),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
|
||||
bb->width, bb->height);
|
||||
}
|
||||
|
||||
static void dma2d_rgb565_blend_mono4_first_col(const gl_bitblt_t* bb) {
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_alpha = src_ptr[0] >> 4;
|
||||
dst_ptr[0] = gl_color16_blend_a4(bb->src_fg,
|
||||
gl_color16_to_color(dst_ptr[0]), fg_alpha);
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma2d_rgb565_blend_mono4_last_col(const gl_bitblt_t* bb) {
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_alpha = src_ptr[0] & 0x0F;
|
||||
dst_ptr[0] = gl_color16_blend_a4(bb->src_fg,
|
||||
gl_color16_to_color(dst_ptr[0]), fg_alpha);
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void dma2d_rgb565_blend_mono4(const gl_bitblt_t* params) {
|
||||
dma2d_wait();
|
||||
|
||||
gl_bitblt_t bb_copy = *params;
|
||||
gl_bitblt_t* bb = &bb_copy;
|
||||
|
||||
if (bb->src_x & 1) {
|
||||
// First column of mono4 bitmap is odd
|
||||
// Use the CPU to draw the first column
|
||||
dma2d_rgb565_blend_mono4_first_col(bb);
|
||||
bb->dst_x += 1;
|
||||
bb->src_x += 1;
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
if (bb->width > 0 && bb->width & 1) {
|
||||
// The width is odd
|
||||
// Use the CPU to draw the last column
|
||||
dma2d_rgb565_blend_mono4_last_col(bb);
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
if (bb->width > 0) {
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_RGB565;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
|
||||
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = gl_color_to_color32(bb->src_fg);
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_RGB565;
|
||||
dma2d_handle.LayerCfg[0].InputOffset =
|
||||
bb->dst_stride / sizeof(uint16_t) - bb->width;
|
||||
dma2d_handle.LayerCfg[0].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[0].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
|
||||
|
||||
HAL_DMA2D_BlendingStart(
|
||||
&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint16_t), bb->width,
|
||||
bb->height);
|
||||
}
|
||||
}
|
||||
|
||||
void dma2d_rgba8888_fill(const gl_bitblt_t* bb) {
|
||||
dma2d_wait();
|
||||
|
||||
if (bb->src_alpha == 255) {
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
||||
dma2d_handle.Init.Mode = DMA2D_R2M;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
HAL_DMA2D_Start(&dma2d_handle, gl_color_to_color32(bb->src_fg),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
|
||||
bb->width, bb->height);
|
||||
} else {
|
||||
#ifdef STM32U5
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND_FG;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
|
||||
dma2d_handle.LayerCfg[1].InputOffset = 0;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = bb->src_alpha;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
|
||||
dma2d_handle.LayerCfg[0].InputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
dma2d_handle.LayerCfg[0].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[0].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
|
||||
|
||||
HAL_DMA2D_BlendingStart(
|
||||
&dma2d_handle, gl_color_to_color32(bb->src_fg),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t), bb->width,
|
||||
bb->height);
|
||||
#else
|
||||
// STM32F4 can not accelerate blending with the fixed color
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
uint8_t alpha = bb->src_alpha;
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color32_blend_a8(
|
||||
bb->src_fg, gl_color32_to_color(dst_ptr[x]), alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void dma2d_rgba8888_copy_mono4_first_col(gl_bitblt_t* bb,
|
||||
const gl_color32_t* gradient) {
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_lum = src_ptr[0] >> 4;
|
||||
dst_ptr[0] = gradient[fg_lum];
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma2d_rgba8888_copy_mono4_last_col(gl_bitblt_t* bb,
|
||||
const gl_color32_t* gradient) {
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_lum = src_ptr[0] & 0x0F;
|
||||
dst_ptr[0] = gradient[fg_lum];
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void dma2d_rgba8888_copy_mono4(const gl_bitblt_t* params) {
|
||||
const gl_color32_t* src_gradient = NULL;
|
||||
|
||||
gl_bitblt_t bb_copy = *params;
|
||||
gl_bitblt_t* bb = &bb_copy;
|
||||
|
||||
dma2d_wait();
|
||||
|
||||
if (bb->src_x & 1) {
|
||||
// First column of mono4 bitmap is odd
|
||||
// Use the CPU to draw the first column
|
||||
src_gradient = gl_color32_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
dma2d_rgba8888_copy_mono4_first_col(bb, src_gradient);
|
||||
bb->dst_x += 1;
|
||||
bb->src_x += 1;
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
if (bb->width > 0 && bb->width & 1) {
|
||||
// The width is odd
|
||||
// Use the CPU to draw the last column
|
||||
if (src_gradient == NULL) {
|
||||
src_gradient = gl_color32_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
}
|
||||
dma2d_rgba8888_copy_mono4_last_col(bb, src_gradient);
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_L4;
|
||||
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
dma2d_config_clut(1, bb->src_fg, bb->src_bg);
|
||||
|
||||
HAL_DMA2D_Start(&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
|
||||
bb->width, bb->height);
|
||||
}
|
||||
|
||||
void dma2d_rgba8888_copy_rgb565(const gl_bitblt_t* bb) {
|
||||
dma2d_wait();
|
||||
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_RGB565;
|
||||
dma2d_handle.LayerCfg[1].InputOffset =
|
||||
bb->src_stride / sizeof(uint16_t) - bb->width;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
HAL_DMA2D_Start(&dma2d_handle,
|
||||
(uint32_t)bb->src_row + bb->src_x * sizeof(uint16_t),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
|
||||
bb->width, bb->height);
|
||||
}
|
||||
|
||||
static void dma2d_rgba8888_blend_mono4_first_col(const gl_bitblt_t* bb) {
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_alpha = src_ptr[0] >> 4;
|
||||
dst_ptr[0] = gl_color32_blend_a4(bb->src_fg,
|
||||
gl_color32_to_color(dst_ptr[0]), fg_alpha);
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
static void dma2d_rgba8888_blend_mono4_last_col(const gl_bitblt_t* bb) {
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + (bb->dst_x + bb->width - 1);
|
||||
uint8_t* src_ptr = (uint8_t*)bb->src_row + (bb->src_x + bb->width - 1) / 2;
|
||||
|
||||
int height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
uint8_t fg_alpha = src_ptr[0] & 0x0F;
|
||||
dst_ptr[0] = gl_color32_blend_a4(bb->src_fg,
|
||||
gl_color32_to_color(dst_ptr[0]), fg_alpha);
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void dma2d_rgba8888_blend_mono4(const gl_bitblt_t* params) {
|
||||
dma2d_wait();
|
||||
|
||||
gl_bitblt_t bb_copy = *params;
|
||||
gl_bitblt_t* bb = &bb_copy;
|
||||
|
||||
if (bb->src_x & 1) {
|
||||
// First column of mono4 bitmap is odd
|
||||
// Use the CPU to draw the first column
|
||||
dma2d_rgba8888_blend_mono4_first_col(bb);
|
||||
bb->dst_x += 1;
|
||||
bb->src_x += 1;
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
if (bb->width > 0 && bb->width & 1) {
|
||||
// The width is odd
|
||||
// Use the CPU to draw the last column
|
||||
dma2d_rgba8888_blend_mono4_last_col(bb);
|
||||
bb->width -= 1;
|
||||
}
|
||||
|
||||
if (bb->width > 0) {
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_BLEND;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_A4;
|
||||
dma2d_handle.LayerCfg[1].InputOffset = bb->src_stride * 2 - bb->width;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = gl_color_to_color32(bb->src_fg);
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
dma2d_handle.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888;
|
||||
dma2d_handle.LayerCfg[0].InputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
dma2d_handle.LayerCfg[0].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[0].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 0);
|
||||
|
||||
HAL_DMA2D_BlendingStart(
|
||||
&dma2d_handle, (uint32_t)bb->src_row + bb->src_x / 2,
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t), bb->width,
|
||||
bb->height);
|
||||
}
|
||||
}
|
||||
|
||||
void dma2d_rgba8888_copy_rgba8888(const gl_bitblt_t* bb) {
|
||||
dma2d_wait();
|
||||
|
||||
dma2d_handle.Init.ColorMode = DMA2D_OUTPUT_ARGB8888;
|
||||
dma2d_handle.Init.Mode = DMA2D_M2M_PFC;
|
||||
dma2d_handle.Init.OutputOffset =
|
||||
bb->dst_stride / sizeof(uint32_t) - bb->width;
|
||||
HAL_DMA2D_Init(&dma2d_handle);
|
||||
|
||||
dma2d_handle.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888;
|
||||
dma2d_handle.LayerCfg[1].InputOffset =
|
||||
bb->src_stride / sizeof(uint32_t) - bb->width;
|
||||
dma2d_handle.LayerCfg[1].AlphaMode = 0;
|
||||
dma2d_handle.LayerCfg[1].InputAlpha = 0;
|
||||
HAL_DMA2D_ConfigLayer(&dma2d_handle, 1);
|
||||
|
||||
HAL_DMA2D_Start(&dma2d_handle,
|
||||
(uint32_t)bb->src_row + bb->src_x * sizeof(uint32_t),
|
||||
(uint32_t)bb->dst_row + bb->dst_x * sizeof(uint32_t),
|
||||
bb->width, bb->height);
|
||||
}
|
@ -0,0 +1 @@
|
||||
../../stm32f4/display/st-7789
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "display_internal.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
#if (DISPLAY_RESX != 240) || (DISPLAY_RESY != 240)
|
||||
#error "Incompatible display resolution"
|
||||
#endif
|
||||
|
||||
// Display driver context.
|
||||
typedef struct {
|
||||
// Current display orientation (0, 90, 180, 270)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
} display_driver_t;
|
||||
|
||||
// Display driver instance
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
void display_init(void) {
|
||||
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
|
||||
|
||||
// Initializes the common periph clock
|
||||
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_LTDC | RCC_PERIPHCLK_DSI;
|
||||
PeriphClkInit.DsiClockSelection = RCC_DSICLKSOURCE_PLL3;
|
||||
PeriphClkInit.LtdcClockSelection = RCC_LTDCCLKSOURCE_PLL3;
|
||||
PeriphClkInit.PLL3.PLL3Source = RCC_PLLSOURCE_HSE;
|
||||
PeriphClkInit.PLL3.PLL3M = 4;
|
||||
PeriphClkInit.PLL3.PLL3N = 125;
|
||||
PeriphClkInit.PLL3.PLL3P = 8;
|
||||
PeriphClkInit.PLL3.PLL3Q = 2;
|
||||
PeriphClkInit.PLL3.PLL3R = 24;
|
||||
PeriphClkInit.PLL3.PLL3RGE = RCC_PLLVCIRANGE_0;
|
||||
PeriphClkInit.PLL3.PLL3FRACN = 0;
|
||||
PeriphClkInit.PLL3.PLL3ClockOut = RCC_PLL3_DIVP | RCC_PLL3_DIVR;
|
||||
HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit);
|
||||
|
||||
// Clear framebuffers
|
||||
memset(physical_frame_buffer_0, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
|
||||
memset(physical_frame_buffer_1, 0x00, PHYSICAL_FRAME_BUFFER_SIZE);
|
||||
|
||||
BSP_LCD_Init(0, LCD_ORIENTATION_PORTRAIT);
|
||||
BSP_LCD_SetBrightness(0, 100);
|
||||
BSP_LCD_DisplayOn(0);
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
BSP_LCD_Reinit(0);
|
||||
if (current_frame_buffer == 0) {
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
|
||||
} else {
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
|
||||
}
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
// Not used and intentionally left empty
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
// Just emulation, not doing anything
|
||||
drv->backlight_level = level;
|
||||
return level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
// Just emulation, not doing anything
|
||||
drv->orientation_angle = angle;
|
||||
}
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
void display_set_compatible_settings() {}
|
||||
|
||||
void display_fill(const gl_bitblt_t *bb) {
|
||||
display_fb_info_t fb = display_get_frame_buffer();
|
||||
|
||||
gl_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;
|
||||
|
||||
gl_rgba8888_fill(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_rgb565(const gl_bitblt_t *bb) {
|
||||
display_fb_info_t fb = display_get_frame_buffer();
|
||||
|
||||
gl_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;
|
||||
|
||||
gl_rgba8888_copy_rgb565(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_mono1p(const gl_bitblt_t *bb) {
|
||||
display_fb_info_t fb = display_get_frame_buffer();
|
||||
|
||||
gl_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;
|
||||
|
||||
gl_rgba8888_copy_mono1p(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_mono4(const gl_bitblt_t *bb) {
|
||||
display_fb_info_t fb = display_get_frame_buffer();
|
||||
|
||||
gl_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;
|
||||
|
||||
gl_rgba8888_copy_mono4(&bb_new);
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include TREZOR_BOARD
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include <xdisplay.h>
|
||||
#include "display_internal.h"
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
__attribute__((section(".fb1")))
|
||||
ALIGN_32BYTES(uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
__attribute__((section(".fb2")))
|
||||
ALIGN_32BYTES(uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE]);
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
// It's shared between bootloaders and the firmware
|
||||
__attribute__((section(".framebuffer_select"))) uint32_t current_frame_buffer =
|
||||
0;
|
||||
|
||||
display_fb_info_t display_get_frame_buffer(void) {
|
||||
uintptr_t addr;
|
||||
|
||||
if (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;
|
||||
|
||||
display_fb_info_t fb = {
|
||||
.ptr = (void *)addr,
|
||||
.stride = fb_stride,
|
||||
};
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
void display_refresh(void) {
|
||||
if (current_frame_buffer == 0) {
|
||||
current_frame_buffer = 1;
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER1_BASE_S);
|
||||
memcpy(physical_frame_buffer_0, physical_frame_buffer_1,
|
||||
sizeof(physical_frame_buffer_0));
|
||||
} else {
|
||||
current_frame_buffer = 0;
|
||||
BSP_LCD_SetFrameBuffer(0, GFXMMU_VIRTUAL_BUFFER0_BASE_S);
|
||||
memcpy(physical_frame_buffer_1, physical_frame_buffer_0,
|
||||
sizeof(physical_frame_buffer_1));
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
#define TREZOR_HAL_DISPLAY_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Size of the physical frame buffer in bytes
|
||||
//
|
||||
// It's smaller than size of the virtual frame buffer
|
||||
// due to used GFXMMU settings
|
||||
#define PHYSICAL_FRAME_BUFFER_SIZE 184320
|
||||
|
||||
// Pitch (in pixels) of the virtual frame buffer
|
||||
#define FRAME_BUFFER_PIXELS_PER_LINE 768
|
||||
|
||||
// Physical frame buffers in internal SRAM memory
|
||||
//
|
||||
// Both frame buffers layes in the fixed addresses that
|
||||
// are shared between bootloaders and the firmware.
|
||||
extern uint32_t physical_frame_buffer_0[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
extern uint32_t physical_frame_buffer_1[PHYSICAL_FRAME_BUFFER_SIZE];
|
||||
|
||||
// The current frame buffer selector at fixed memory address
|
||||
//
|
||||
// The variable address is shared between bootloaders and the firmware
|
||||
extern uint32_t current_frame_buffer;
|
||||
|
||||
// LCD orientations
|
||||
#define LCD_ORIENTATION_PORTRAIT 0U
|
||||
#define LCD_ORIENTATION_LANDSCAPE 1U
|
||||
#define LCD_ORIENTATION_PORTRAIT_ROT180 2U
|
||||
#define LCD_ORIENTATION_LANDSCAPE_ROT180 3U
|
||||
|
||||
int32_t BSP_LCD_Init(uint32_t Instance, uint32_t Orientation);
|
||||
int32_t BSP_LCD_Reinit(uint32_t Instance);
|
||||
int32_t BSP_LCD_SetBrightness(uint32_t Instance, uint32_t Brightness);
|
||||
int32_t BSP_LCD_DisplayOn(uint32_t Instance);
|
||||
int32_t BSP_LCD_SetFrameBuffer(uint32_t Instance, uint32_t fb_addr);
|
||||
|
||||
#endif // TREZOR_HAL_DISPLAY_INTERNAL_H
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1 @@
|
||||
../../stm32f4/display/vg-2864
|
@ -0,0 +1 @@
|
||||
../stm32f4/dma2d_bitblt.c
|
@ -0,0 +1,461 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <xdisplay.h>
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "profile.h"
|
||||
|
||||
#define EMULATOR_BORDER 16
|
||||
|
||||
#if defined TREZOR_MODEL_T
|
||||
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
#define WINDOW_WIDTH 480
|
||||
#define WINDOW_HEIGHT 320
|
||||
#define TOUCH_OFFSET_X 110
|
||||
#define TOUCH_OFFSET_Y 40
|
||||
#else
|
||||
#define WINDOW_WIDTH 400
|
||||
#define WINDOW_HEIGHT 600
|
||||
#define TOUCH_OFFSET_X 80
|
||||
#define TOUCH_OFFSET_Y 110
|
||||
#endif
|
||||
|
||||
#elif defined TREZOR_MODEL_1
|
||||
|
||||
#define WINDOW_WIDTH 200
|
||||
#define WINDOW_HEIGHT 340
|
||||
#define TOUCH_OFFSET_X 36
|
||||
#define TOUCH_OFFSET_Y 92
|
||||
|
||||
#elif defined TREZOR_MODEL_R
|
||||
|
||||
#define WINDOW_WIDTH 193
|
||||
#define WINDOW_HEIGHT 339
|
||||
#define TOUCH_OFFSET_X 32
|
||||
#define TOUCH_OFFSET_Y 84
|
||||
|
||||
#elif defined TREZOR_MODEL_T3T1
|
||||
|
||||
#define WINDOW_WIDTH 400
|
||||
#define WINDOW_HEIGHT 600
|
||||
#define TOUCH_OFFSET_X 80
|
||||
#define TOUCH_OFFSET_Y 110
|
||||
|
||||
#else
|
||||
#error Unknown Trezor model
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// Current display orientation (0 or 180)
|
||||
int orientation_angle;
|
||||
// Current backlight level ranging from 0 to 255
|
||||
int backlight_level;
|
||||
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
SDL_Surface *buffer;
|
||||
SDL_Texture *texture;
|
||||
SDL_Texture *background;
|
||||
SDL_Surface *prev_saved;
|
||||
|
||||
#if DISPLAY_MONO
|
||||
// SDL2 does not support 8bit surface/texture
|
||||
// and we have to simulate it
|
||||
uint8_t mono_framebuf[DISPLAY_RESX * DISPLAY_RESY];
|
||||
#endif
|
||||
|
||||
} display_driver_t;
|
||||
|
||||
static display_driver_t g_display_driver;
|
||||
|
||||
//!@# TODO get rid of this...
|
||||
int sdl_display_res_x = DISPLAY_RESX, sdl_display_res_y = DISPLAY_RESY;
|
||||
int sdl_touch_offset_x, sdl_touch_offset_y;
|
||||
|
||||
void display_deinit(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
SDL_FreeSurface(drv->prev_saved);
|
||||
SDL_FreeSurface(drv->buffer);
|
||||
if (drv->background != NULL) {
|
||||
SDL_DestroyTexture(drv->background);
|
||||
}
|
||||
if (drv->texture != NULL) {
|
||||
SDL_DestroyTexture(drv->texture);
|
||||
}
|
||||
if (drv->renderer != NULL) {
|
||||
SDL_DestroyRenderer(drv->renderer);
|
||||
}
|
||||
if (drv->window != NULL) {
|
||||
SDL_DestroyWindow(drv->window);
|
||||
}
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void display_init(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||
printf("%s\n", SDL_GetError());
|
||||
ensure(secfalse, "SDL_Init error");
|
||||
}
|
||||
atexit(display_deinit);
|
||||
|
||||
char *window_title = NULL;
|
||||
char *window_title_alloc = NULL;
|
||||
if (asprintf(&window_title_alloc, "Trezor^emu: %s", profile_name()) > 0) {
|
||||
window_title = window_title_alloc;
|
||||
} else {
|
||||
window_title = "Trezor^emu";
|
||||
window_title_alloc = NULL;
|
||||
}
|
||||
|
||||
drv->window =
|
||||
SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED, WINDOW_WIDTH, WINDOW_HEIGHT,
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN
|
||||
#else
|
||||
SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI
|
||||
#endif
|
||||
);
|
||||
free(window_title_alloc);
|
||||
if (!drv->window) {
|
||||
printf("%s\n", SDL_GetError());
|
||||
ensure(secfalse, "SDL_CreateWindow error");
|
||||
}
|
||||
drv->renderer = SDL_CreateRenderer(drv->window, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (!drv->renderer) {
|
||||
printf("%s\n", SDL_GetError());
|
||||
SDL_DestroyWindow(drv->window);
|
||||
ensure(secfalse, "SDL_CreateRenderer error");
|
||||
}
|
||||
SDL_SetRenderDrawColor(drv->renderer, 0, 0, 0, 255);
|
||||
SDL_RenderClear(drv->renderer);
|
||||
|
||||
drv->buffer = SDL_CreateRGBSurface(0, DISPLAY_RESX, DISPLAY_RESY, 16, 0xF800,
|
||||
0x07E0, 0x001F, 0x0000);
|
||||
drv->texture = SDL_CreateTexture(drv->renderer, SDL_PIXELFORMAT_RGB565,
|
||||
SDL_TEXTUREACCESS_STREAMING, DISPLAY_RESX,
|
||||
DISPLAY_RESY);
|
||||
SDL_SetTextureBlendMode(drv->texture, SDL_BLENDMODE_BLEND);
|
||||
#ifdef __APPLE__
|
||||
// macOS Mojave SDL black screen workaround
|
||||
SDL_PumpEvents();
|
||||
SDL_SetWindowSize(drv->window, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
#endif
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
#include "background_raspi.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer,
|
||||
SDL_RWFromMem(background_raspi_jpg, background_raspi_jpg_len), 0);
|
||||
#else
|
||||
#if defined TREZOR_MODEL_T
|
||||
#include "background_T.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer, SDL_RWFromMem(background_T_jpg, background_T_jpg_len), 0);
|
||||
#elif defined TREZOR_MODEL_1
|
||||
#include "background_1.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer, SDL_RWFromMem(background_1_jpg, background_1_jpg_len), 0);
|
||||
#elif defined TREZOR_MODEL_R
|
||||
#include "background_T2B1.h"
|
||||
drv->background = IMG_LoadTexture_RW(
|
||||
drv->renderer,
|
||||
SDL_RWFromMem(background_T2B1_png, background_T2B1_png_len), 0);
|
||||
#endif
|
||||
#endif
|
||||
if (drv->background) {
|
||||
SDL_SetTextureBlendMode(drv->background, SDL_BLENDMODE_NONE);
|
||||
sdl_touch_offset_x = TOUCH_OFFSET_X;
|
||||
sdl_touch_offset_y = TOUCH_OFFSET_Y;
|
||||
} else {
|
||||
SDL_SetWindowSize(drv->window, DISPLAY_RESX + 2 * EMULATOR_BORDER,
|
||||
DISPLAY_RESY + 2 * EMULATOR_BORDER);
|
||||
sdl_touch_offset_x = EMULATOR_BORDER;
|
||||
sdl_touch_offset_y = EMULATOR_BORDER;
|
||||
}
|
||||
#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
// T1 and TR do not have backlight capabilities in hardware, so
|
||||
// setting its value here for emulator to avoid
|
||||
// calling any `set_backlight` functions
|
||||
drv->backlight_level = 255;
|
||||
#else
|
||||
drv->backlight_level = 0;
|
||||
#endif
|
||||
#ifdef TREZOR_EMULATOR_RASPI
|
||||
drv->orientation_angle = 270;
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
#else
|
||||
drv->orientation_angle = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void display_reinit(void) {
|
||||
// not used
|
||||
}
|
||||
|
||||
void display_finish_actions(void) {
|
||||
// not used
|
||||
}
|
||||
|
||||
int display_set_backlight(int level) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
#if defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
level = 255;
|
||||
#endif
|
||||
|
||||
if (drv->backlight_level != level && level >= 0 && level <= 255) {
|
||||
drv->backlight_level = level;
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_get_backlight(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
return drv->backlight_level;
|
||||
}
|
||||
|
||||
int display_set_orientation(int angle) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
if (angle != drv->orientation_angle) {
|
||||
#if defined TREZOR_MODEL_T || defined TREZOR_MODEL_T3T1
|
||||
if (angle == 0 || angle == 90 || angle == 180 || angle == 270) {
|
||||
#elif defined TREZOR_MODEL_1 || defined TREZOR_MODEL_R
|
||||
if (angle == 0 || angle == 180) {
|
||||
#else
|
||||
#error Unknown Trezor model
|
||||
#endif
|
||||
drv->orientation_angle = angle;
|
||||
display_refresh();
|
||||
}
|
||||
}
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
int display_get_orientation(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
return drv->orientation_angle;
|
||||
}
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
display_fb_info_t display_get_frame_buffer(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
#ifdef DISPLAY_MONO
|
||||
display_fb_info_t fb = {
|
||||
.ptr = drv->mono_framebuf,
|
||||
.stride = DISPLAY_RESX,
|
||||
};
|
||||
#else
|
||||
display_fb_info_t fb = {
|
||||
.ptr = drv->buffer->pixels,
|
||||
.stride = DISPLAY_RESX * sizeof(uint16_t),
|
||||
};
|
||||
#endif
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
#else // XFRAMEBUFFER
|
||||
|
||||
void display_wait_for_sync(void) {
|
||||
// not used
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DISPLAY_MONO
|
||||
// Copies driver's monochromatic framebuffer into the RGB framebuffer used by
|
||||
// SDL
|
||||
static void copy_mono_framebuf(display_driver_t *drv) {
|
||||
for (int y = 0; y < DISPLAY_RESY; y++) {
|
||||
uint16_t *dst =
|
||||
(uint16_t *)((uint8_t *)drv->buffer->pixels + drv->buffer->pitch * y);
|
||||
uint8_t *src = &drv->mono_framebuf[y * DISPLAY_RESX];
|
||||
for (int x = 0; x < DISPLAY_RESX; x++) {
|
||||
uint8_t lum = src[x] > 40 ? 255 : 0;
|
||||
dst[x] = gl_color16_rgb(lum, lum, lum);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void display_refresh(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (!drv->renderer) {
|
||||
display_init();
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_MONO
|
||||
copy_mono_framebuf(drv);
|
||||
#endif
|
||||
|
||||
if (drv->background) {
|
||||
const SDL_Rect r = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
|
||||
SDL_RenderCopy(drv->renderer, drv->background, NULL, &r);
|
||||
} else {
|
||||
SDL_RenderClear(drv->renderer);
|
||||
}
|
||||
// Show the display buffer
|
||||
SDL_UpdateTexture(drv->texture, NULL, drv->buffer->pixels,
|
||||
drv->buffer->pitch);
|
||||
#define BACKLIGHT_NORMAL 150
|
||||
SDL_SetTextureAlphaMod(
|
||||
drv->texture, MIN(255, 255 * drv->backlight_level / BACKLIGHT_NORMAL));
|
||||
if (drv->background) {
|
||||
const SDL_Rect r = {TOUCH_OFFSET_X, TOUCH_OFFSET_Y, DISPLAY_RESX,
|
||||
DISPLAY_RESY};
|
||||
SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r,
|
||||
drv->orientation_angle, NULL, 0);
|
||||
} else {
|
||||
const SDL_Rect r = {EMULATOR_BORDER, EMULATOR_BORDER, DISPLAY_RESX,
|
||||
DISPLAY_RESY};
|
||||
SDL_RenderCopyEx(drv->renderer, drv->texture, NULL, &r,
|
||||
drv->orientation_angle, NULL, 0);
|
||||
}
|
||||
SDL_RenderPresent(drv->renderer);
|
||||
}
|
||||
|
||||
void display_set_compatible_settings(void) {
|
||||
// not used
|
||||
}
|
||||
|
||||
#ifndef DISPLAY_MONO
|
||||
|
||||
void display_fill(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row =
|
||||
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
|
||||
bb_new.dst_stride = drv->buffer->pitch;
|
||||
|
||||
gl_rgb565_fill(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_rgb565(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row =
|
||||
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
|
||||
bb_new.dst_stride = drv->buffer->pitch;
|
||||
|
||||
gl_rgb565_copy_rgb565(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_mono1p(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row =
|
||||
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
|
||||
bb_new.dst_stride = DISPLAY_RESX;
|
||||
|
||||
gl_rgb565_copy_mono1p(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_mono4(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row =
|
||||
(uint8_t *)drv->buffer->pixels + (drv->buffer->pitch * bb_new.dst_y);
|
||||
bb_new.dst_stride = drv->buffer->pitch;
|
||||
|
||||
gl_rgb565_copy_mono4(&bb_new);
|
||||
}
|
||||
|
||||
#else // DISPLAY_MONO
|
||||
|
||||
void display_fill(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row = drv->mono_framebuf + (DISPLAY_RESX * bb_new.dst_y);
|
||||
bb_new.dst_stride = DISPLAY_RESX;
|
||||
|
||||
gl_mono8_fill(&bb_new);
|
||||
}
|
||||
|
||||
void display_copy_mono1p(const gl_bitblt_t *bb) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
gl_bitblt_t bb_new = *bb;
|
||||
bb_new.dst_row = drv->mono_framebuf + (DISPLAY_RESX * bb_new.dst_y);
|
||||
bb_new.dst_stride = DISPLAY_RESX;
|
||||
|
||||
gl_mono8_copy_mono1p(&bb_new);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const char *display_save(const char *prefix) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
if (!drv->renderer) {
|
||||
display_init();
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_MONO
|
||||
copy_mono_framebuf(drv);
|
||||
#endif
|
||||
|
||||
static int count;
|
||||
static char filename[256];
|
||||
// take a cropped view of the screen contents
|
||||
const SDL_Rect rect = {0, 0, DISPLAY_RESX, DISPLAY_RESY};
|
||||
SDL_Surface *crop = SDL_CreateRGBSurface(
|
||||
drv->buffer->flags, rect.w, rect.h, drv->buffer->format->BitsPerPixel,
|
||||
drv->buffer->format->Rmask, drv->buffer->format->Gmask,
|
||||
drv->buffer->format->Bmask, drv->buffer->format->Amask);
|
||||
SDL_BlitSurface(drv->buffer, &rect, crop, NULL);
|
||||
// compare with previous screen, skip if equal
|
||||
if (drv->prev_saved != NULL) {
|
||||
if (memcmp(drv->prev_saved->pixels, crop->pixels, crop->pitch * crop->h) ==
|
||||
0) {
|
||||
SDL_FreeSurface(crop);
|
||||
return filename;
|
||||
}
|
||||
SDL_FreeSurface(drv->prev_saved);
|
||||
}
|
||||
// save to png
|
||||
snprintf(filename, sizeof(filename), "%s%08d.png", prefix, count++);
|
||||
IMG_SavePNG(crop, filename);
|
||||
drv->prev_saved = crop;
|
||||
return filename;
|
||||
}
|
||||
|
||||
void display_clear_save(void) {
|
||||
display_driver_t *drv = &g_display_driver;
|
||||
|
||||
SDL_FreeSurface(drv->prev_saved);
|
||||
drv->prev_saved = NULL;
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 "dma2d_bitblt.h"
|
||||
|
||||
void dma2d_wait(void) {}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_XDISPLAY_H
|
||||
#define TREZORHAL_XDISPLAY_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include "gl_bitblt.h"
|
||||
|
||||
#include TREZOR_BOARD
|
||||
|
||||
// This is a universal API for controlling different types of display
|
||||
// controllers.
|
||||
//
|
||||
// Currently, following displays displays are supported
|
||||
//
|
||||
// VG-2864KSWEG01 - OLED Mono / 128x64 pixels / SPI
|
||||
// - Model T1B1 / Model T2B1
|
||||
//
|
||||
// UG-2828SWIG01 - OLED Mono / 128x128 pixels / Parallel
|
||||
// - Early revisions of T2B1
|
||||
//
|
||||
// ST7789V - TFT RGB / 240x240 pixels / Parallel
|
||||
// - Model T2T1 / Model T3T1
|
||||
//
|
||||
// ILI9341 - TFT RGB / 320x240 pixels / Parallel / LTDC + SPI
|
||||
// - STM32F429I-DISC1 Discovery Board
|
||||
//
|
||||
// MIPI -
|
||||
// - STM32U5A9J-DK Discovery Board
|
||||
|
||||
// Fully initializes the display controller.
|
||||
void display_init(void);
|
||||
|
||||
// Called in application or bootloader to reinitialize an already initialized
|
||||
// display controller without any distrubing visible effect (blinking, etc.).
|
||||
void display_reinit(void);
|
||||
|
||||
// Waits for any backround operations (such as DMA copying) and returns.
|
||||
//
|
||||
// The function provides a barrier when jumping between
|
||||
// boardloader/bootloader and firmware.
|
||||
void display_finish_actions(void);
|
||||
|
||||
// Sets display backlight level ranging from 0 (off)..255 (maximum).
|
||||
//
|
||||
// The default backligt level is 0. Without settings it
|
||||
// to some higher value the displayed pixels are not visible.
|
||||
// Beware that his also applies to the emulator.
|
||||
//
|
||||
// Returns the set level (usually the same value or the
|
||||
// closest value to the `level` argument)
|
||||
int display_set_backlight(int level);
|
||||
|
||||
// Gets current display level ranging from 0 (off)..255 (maximum).
|
||||
int display_get_backlight(void);
|
||||
|
||||
// Sets the display orientation.
|
||||
//
|
||||
// May accept one of following values: 0, 90, 180, 270
|
||||
// but accepted values are model-dependent.
|
||||
// Default display orientation is always 0.
|
||||
//
|
||||
// Returns the set orientation
|
||||
int display_set_orientation(int angle);
|
||||
|
||||
// Gets the display's current orientation
|
||||
//
|
||||
// Returned value is one of 0, 90, 180, 270.
|
||||
int display_get_orientation(void);
|
||||
|
||||
#ifdef XFRAMEBUFFER
|
||||
|
||||
typedef struct {
|
||||
// Pointer to the top-left pixel
|
||||
void *ptr;
|
||||
// Stride in bytes
|
||||
size_t stride;
|
||||
|
||||
} display_fb_info_t;
|
||||
|
||||
// Provides pointer to the inactive (writeable) framebuffer.
|
||||
//
|
||||
// If framebuffer is not available yet due to display refreshing etc.,
|
||||
// the function may block until the buffer is ready to write.
|
||||
display_fb_info_t display_get_frame_buffer(void);
|
||||
|
||||
#else // XFRAMEBUFFER
|
||||
|
||||
// Waits for the vertical synchronization pulse.
|
||||
//
|
||||
// Used for synchronization with the display refresh cycle
|
||||
// to achieve tearless UX if possible when not using a frame buffer.
|
||||
void display_wait_for_sync(void);
|
||||
#endif
|
||||
|
||||
// Swaps the frame buffers
|
||||
//
|
||||
// The function waits for vertical synchronization and
|
||||
// swaps the active (currently displayed) and the inactive frame buffers.
|
||||
void display_refresh(void);
|
||||
|
||||
// Sets display to the mode compatible with the legacy bootloader code.
|
||||
//
|
||||
// This is used when switching between the firmware and the bootloader.
|
||||
void display_set_compatible_settings(void);
|
||||
|
||||
// Following function define display's bitblt interface.
|
||||
//
|
||||
// These functions draw directly to to display or to the
|
||||
// currently inactive framebuffer.
|
||||
//
|
||||
// bb->dst_row and bb->dst_stride must be 0
|
||||
|
||||
// Fills a rectangle with a solid color
|
||||
void display_fill(const gl_bitblt_t *bb);
|
||||
// Copies an RGB565 bitmap
|
||||
void display_copy_rgb565(const gl_bitblt_t *bb);
|
||||
// Copies a MONO4 bitmap
|
||||
void display_copy_mono4(const gl_bitblt_t *bb);
|
||||
// Copies a MONO1P bitmap
|
||||
void display_copy_mono1p(const gl_bitblt_t *bb);
|
||||
|
||||
#ifdef TREZOR_EMULATOR
|
||||
// Save the screen content to a file.
|
||||
// The function is available only on the emulator.
|
||||
const char *display_save(const char *prefix);
|
||||
void display_clear_save(void);
|
||||
#endif
|
||||
|
||||
// Adds some declarations needed to compile with the legacy code
|
||||
// (will be removed with the display legacy code)
|
||||
#include "xdisplay_legacy.h"
|
||||
|
||||
#endif // TREZORHAL_XDISPLAY_H
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 "xdisplay_legacy.h"
|
||||
#include "xdisplay.h"
|
||||
|
||||
// This code emulates the legacy display interface and will be
|
||||
// removed after final cleanup of display drivers when the legacy code
|
||||
// is removed.
|
||||
|
||||
int display_orientation(int angle) {
|
||||
if (angle >= 0) {
|
||||
return display_set_orientation(angle);
|
||||
} else {
|
||||
return display_get_orientation();
|
||||
}
|
||||
}
|
||||
|
||||
int display_backlight(int level) {
|
||||
if (level >= 0) {
|
||||
return display_set_backlight(level);
|
||||
} else {
|
||||
return display_get_backlight();
|
||||
}
|
||||
}
|
||||
|
||||
void display_sync(void) {}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TREZORHAL_DISPLAY_LEGACY_H
|
||||
#define TREZORHAL_DISPLAY_LEGACY_H
|
||||
|
||||
#include <buffers.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// These declarationscode emulates will be removed after the
|
||||
// final cleanup of display drivers. They are here just to simplify
|
||||
// integration with the legacy code.
|
||||
//
|
||||
// Most of these function are not called when NEW_RENDERING=1
|
||||
// and they are only needed to for succesfully code compilation
|
||||
|
||||
#define DISPLAY_FRAMEBUFFER_WIDTH 768
|
||||
#define DISPLAY_FRAMEBUFFER_HEIGHT 480
|
||||
#define DISPLAY_FRAMEBUFFER_OFFSET_X 0
|
||||
#define DISPLAY_FRAMEBUFFER_OFFSET_Y 0
|
||||
|
||||
int display_orientation(int angle);
|
||||
int display_backlight(int level);
|
||||
void display_refresh(void);
|
||||
void display_shift_window(uint16_t pixels);
|
||||
uint16_t display_get_window_offset(void);
|
||||
void display_pixeldata_dirty(void);
|
||||
uint8_t* display_get_wr_addr(void);
|
||||
void display_sync(void);
|
||||
void display_set_window(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
|
||||
void display_pixeldata(uint16_t c);
|
||||
uint32_t* display_get_fb_addr(void);
|
||||
|
||||
void display_clear(void);
|
||||
void display_text_render_buffer(const char* text, int textlen, int font,
|
||||
buffer_text_t* buffer, int text_offset);
|
||||
|
||||
#define PIXELDATA(c) display_pixeldata(c)
|
||||
|
||||
#endif // TREZORHAL_DISPLAY_LEGACY_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue