feat(core): add support for dem240320b1 display panel
What changed, and why it matters
This commit adds support for a new display panel (DEM240320B1) used in some Trezor hardware wallets. It is purely a hardware-enablement change: it wires up the panel's initialization commands, screen resolution, and rotation handling so the firmware can drive this specific screen. There is no user-facing feature, no change to cryptography, wallet logic, or security boundaries, and no indication of a bug or vulnerability.
No security action required. Treat as normal hardware-support commit. If desired, verify the new panel's gamma/VCOM/frame-rate values against the real hardware, as the commit author already flagged these as initial values that may need tuning.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces a new ST7789 display panel variant, DEM240320B1 (240x320). It adds a Cargo feature flag, build.rs wiring to set DISPLAY_RESX/Y and compile the new panel source, and a new C file/hader pair implementing the panel’s init sequence, gamma table, and rotation logic. The init sequence is adapted from the existing lx154a2482 ST7789 panel and is explicitly noted as a starting point that may need hardware tuning. No existing code behavior is modified; the change is additive and conditional on the new feature flag.
Changed components
core/embed/io/display/st-7789 display drivercore/embed/io/display/build.rscore/embed/io/Cargo.tomlInspect captured patch +215 / −0
diff --git a/core/embed/io/Cargo.toml b/core/embed/io/Cargo.toml
index 9d7ce64a..58240570 100644
--- a/core/embed/io/Cargo.toml
+++ b/core/embed/io/Cargo.toml
@@ -122,5 +122,6 @@ display_panel_lx250a2401a = []
display_panel_stm32u5a9j_dk = []
display_panel_t2t1 = []
display_panel_lx154a2482 = []
+display_panel_dem240320b1 = []
display_panel_vg2864 = []
diff --git a/core/embed/io/display/build.rs b/core/embed/io/display/build.rs
index 4794085d..57a7ff1b 100644
--- a/core/embed/io/display/build.rs
+++ b/core/embed/io/display/build.rs
@@ -67,6 +67,14 @@ fn set_panel_stm32u5a9j_dk(lib: &mut CLibrary) {
]);
}
+fn set_panel_dem240320b1(lib: &mut CLibrary) {
+ lib.add_defines([
+ ("DISPLAY_PANEL_DEM240320B1", Some("1")),
+ ("DISPLAY_RESX", Some("240")),
+ ("DISPLAY_RESY", Some("320")),
+ ]);
+}
+
fn set_panel_lx154a2482(lib: &mut CLibrary) {
lib.add_defines([
("DISPLAY_PANEL_LX154A2482", Some("1")),
@@ -101,6 +109,8 @@ fn add_driver_unix(lib: &mut CLibrary) -> Result<()> {
set_panel_stm32u5a9j_dk(lib);
} else if cfg!(feature = "display_panel_lx154a2482") {
set_panel_lx154a2482(lib);
+ } else if cfg!(feature = "display_panel_dem240320b1") {
+ set_panel_dem240320b1(lib);
} else if cfg!(feature = "display_panel_t2t1") {
set_panel_t2t1(lib);
} else if cfg!(feature = "display_panel_vg2864") {
@@ -160,6 +170,9 @@ fn add_driver_st7789(lib: &mut CLibrary) -> Result<()> {
if cfg!(feature = "display_panel_lx154a2482") {
set_panel_lx154a2482(lib);
lib.add_source("display/st-7789/panels/lx154a2482.c");
+ } else if cfg!(feature = "display_panel_dem240320b1") {
+ set_panel_dem240320b1(lib);
+ lib.add_source("display/st-7789/panels/dem240320b1.c");
} else {
bail_unsupported!();
}
diff --git a/core/embed/io/display/st-7789/display_panel.c b/core/embed/io/display/st-7789/display_panel.c
index fc7b37f2..0cd1b07f 100644
--- a/core/embed/io/display/st-7789/display_panel.c
+++ b/core/embed/io/display/st-7789/display_panel.c
@@ -32,6 +32,11 @@
#define PANEL_INIT_SEQ lx154a2482_init_seq
#define PANEL_ROTATE lx154a2482_rotate
#define PANEL_REINIT lx154a2482_init_seq
+#elif defined(DISPLAY_PANEL_DEM240320B1)
+#include "panels/dem240320b1.h"
+#define PANEL_INIT_SEQ dem240320b1_init_seq
+#define PANEL_ROTATE dem240320b1_rotate
+#define PANEL_REINIT dem240320b1_init_seq
#elif defined(DISPLAY_PANEL_LHS200KB_IF21)
#include "panels/lhs200kb-if21.h"
#define PANEL_INIT_SEQ lhs200kb_if21_init_seq
diff --git a/core/embed/io/display/st-7789/panels/dem240320b1.c b/core/embed/io/display/st-7789/panels/dem240320b1.c
new file mode 100644
index 00000000..9333b0bb
--- /dev/null
+++ b/core/embed/io/display/st-7789/panels/dem240320b1.c
@@ -0,0 +1,167 @@
+/*
+ * 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/>.
+ */
+
+// Display Elektronik DEM240320B1 VTH-PW
+// 2.0" transflective TFT, 240(RGB)x320, controller ST7789 (COG).
+//
+// NOTE: The module datasheet does not provide a register init table, so the
+// sequence below is based on the (same-controller) lx154a2482 ST7789 panel
+// adapted to the full 240x320 resolution. Gamma / VCOM / porch / inversion
+// values are a reasonable starting point and may need tuning against real
+// hardware.
+
+#include <trezor_model.h>
+
+#include "../display_io.h"
+#include "dem240320b1.h"
+
+void dem240320b1_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 dem240320b1_init_seq(void) {
+ // Memory Data Access Control (MADCTL)
+ ISSUE_CMD_BYTE(0x36);
+ ISSUE_DATA_BYTE(0x00);
+
+ // Interface Pixel Format: 16 bits/pixel (RGB565)
+ ISSUE_CMD_BYTE(0x3A);
+ ISSUE_DATA_BYTE(0x05);
+
+ // Column Address Set: 0 .. 239
+ ISSUE_CMD_BYTE(0x2A);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0xEF);
+
+ // Row Address Set: 0 .. 319
+ ISSUE_CMD_BYTE(0x2B);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x01);
+ ISSUE_DATA_BYTE(0x3F);
+
+ // Porch Setting
+ ISSUE_CMD_BYTE(0xB2);
+ ISSUE_DATA_BYTE(0x0C);
+ ISSUE_DATA_BYTE(0x0C);
+ ISSUE_DATA_BYTE(0x00);
+ ISSUE_DATA_BYTE(0x33);
+ ISSUE_DATA_BYTE(0x33);
+
+ // VCOM Setting
+ ISSUE_CMD_BYTE(0xBB);
+ ISSUE_DATA_BYTE(0x1F);
+
+ // LCMCTRL: LCM Control: XOR RGB setting
+ ISSUE_CMD_BYTE(0xC0);
+ ISSUE_DATA_BYTE(0x20);
+
+ // VDV and VRH Command Enable
+ ISSUE_CMD_BYTE(0xC2);
+ ISSUE_DATA_BYTE(0x01);
+
+ // VRH Set
+ ISSUE_CMD_BYTE(0xC3);
+ ISSUE_DATA_BYTE(0x0F); // 4.3V
+
+ // VDV Setting
+ ISSUE_CMD_BYTE(0xC4);
+ ISSUE_DATA_BYTE(0x20);
+
+ // Frame Rate Control in Normal Mode
+ ISSUE_CMD_BYTE(0xC6);
+ ISSUE_DATA_BYTE(0xEF); // column inversion
+
+ // INVON (21h): Display Inversion On (panel is normally black)
+ ISSUE_CMD_BYTE(0x21);
+
+ // PWCTRL1: Power Control 1
+ ISSUE_CMD_BYTE(0xD0);
+ ISSUE_DATA_BYTE(0xA4);
+ ISSUE_DATA_BYTE(0xA1);
+
+ dem240320b1_gamma();
+}
+
+void dem240320b1_rotate(int degrees, display_padding_t* padding) {
+#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;
+ break;
+ case 90:
+ display_command_parameter = MV | MX;
+ break;
+ case 180:
+ display_command_parameter = MX | MY;
+ break;
+ case 270:
+ display_command_parameter = MV | MY;
+ break;
+ }
+
+ ISSUE_CMD_BYTE(0x36);
+ ISSUE_DATA_BYTE(display_command_parameter);
+
+ // Full 240x320 panel - no window offset in any orientation.
+ padding->x = 0;
+ padding->y = 0;
+}
diff --git a/core/embed/io/display/st-7789/panels/dem240320b1.h b/core/embed/io/display/st-7789/panels/dem240320b1.h
new file mode 100644
index 00000000..d1baafc2
--- /dev/null
+++ b/core/embed/io/display/st-7789/panels/dem240320b1.h
@@ -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 DEM240320B1_H_
+#define DEM240320B1_H_
+
+#include "../display_panel.h"
+
+void dem240320b1_init_seq(void);
+void dem240320b1_gamma(void);
+void dem240320b1_rotate(int degrees, display_padding_t* padding);
+
+#endif
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.