feat(core): implementation of backlight brightness correction.
What changed, and why it matters
This commit is a routine hardware driver improvement. It makes the screen backlight brightness curve adjustable per display panel by passing a gamma exponent into the backlight driver. There is no security-relevant change: no memory corruption, no cryptographic code, no privilege changes, and no user data handling.
No security action needed. Treat as normal feature/refactor commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors backlight gamma correction. Previously the tps61062 driver hardcoded GAMMA_CORRECTION 2.2f. Now backlight_init() accepts a float gamma_exp argument, display drivers pass a panel-specific GAMMA_EXP macro (default 1.0f, 2.2f for the lx250a2401a panel), and other backlight drivers simply ignore the new parameter with UNUSED(). The math remains the same for the only driver that actually uses it (tps61062).
Changed components
core/embed/io/backlight driver APIcore/embed/io/display/ltdc_dsi display drivercore/embed/io/display/st-7789 display driverInspect captured patch +54 / −12
diff --git a/core/embed/io/backlight/inc/io/backlight.h b/core/embed/io/backlight/inc/io/backlight.h
index be4fb2a1..ff701d23 100644
--- a/core/embed/io/backlight/inc/io/backlight.h
+++ b/core/embed/io/backlight/inc/io/backlight.h
@@ -37,8 +37,10 @@ typedef enum {
// is set to zero level. If the action is set to `BACKLIGHT_RETAIN`,
// the backlight level is not changed (if possible).
//
+// The `gamma_exp` parameter specifies the gamma_exp correction factor.
+//
// Returns `true` if the initialization was successful.
-bool backlight_init(backlight_action_t action);
+bool backlight_init(backlight_action_t action, float gamma_exp);
// Deinitialize the backlight driver
//
diff --git a/core/embed/io/backlight/stm32/backlight_pin.c b/core/embed/io/backlight/stm32/backlight_pin.c
index b7bf73d1..e21dfecc 100644
--- a/core/embed/io/backlight/stm32/backlight_pin.c
+++ b/core/embed/io/backlight/stm32/backlight_pin.c
@@ -52,9 +52,11 @@ static void backlight_off(void) {
HAL_GPIO_Init(BACKLIGHT_PIN_PORT, &GPIO_InitStructure);
}
-bool backlight_init(backlight_action_t action) {
+bool backlight_init(backlight_action_t action, float gamma_exp) {
backlight_driver_t *drv = &g_backlight_driver;
+ UNUSED(gamma_exp);
+
if (drv->initialized) {
return true;
}
diff --git a/core/embed/io/backlight/stm32/tps61043.c b/core/embed/io/backlight/stm32/tps61043.c
index 148c30c2..365a7aab 100644
--- a/core/embed/io/backlight/stm32/tps61043.c
+++ b/core/embed/io/backlight/stm32/tps61043.c
@@ -45,9 +45,11 @@ static backlight_driver_t g_backlight_driver = {
.initialized = false,
};
-bool backlight_init(backlight_action_t action) {
+bool backlight_init(backlight_action_t action, float gamma_exp) {
backlight_driver_t *drv = &g_backlight_driver;
+ UNUSED(gamma_exp);
+
if (drv->initialized) {
return true;
}
diff --git a/core/embed/io/backlight/stm32u5/tps61062.c b/core/embed/io/backlight/stm32u5/tps61062.c
index f6f59917..7c008a9d 100644
--- a/core/embed/io/backlight/stm32u5/tps61062.c
+++ b/core/embed/io/backlight/stm32u5/tps61062.c
@@ -61,7 +61,6 @@
// API level range 0-255 is mapped to DAC steps 0-31
#define INPUT_OFFSET 1
-#define GAMMA_CORRECTION 2.2f
#define USTEPS_PER_STEP DMA_BUF_LENGTH
#define USTEPS_COUNT (MAX_STEPS * USTEPS_PER_STEP)
@@ -102,6 +101,9 @@ typedef struct {
// Max backlight level
uint8_t max_level;
+ // Gamma exponent
+ float gamma_exp;
+
TIM_HandleTypeDef tim;
DMA_HandleTypeDef dma;
@@ -128,21 +130,38 @@ static void backlight_deinit_ll(void);
static void DMA_XferCpltCallback(DMA_HandleTypeDef *hdma);
-// Brightness level gamma correction - eq: OUT = ( ( (IN - k) / d ) ^ GAMMA) * q
+// Applies gamma correction to a brightness input value.
+//
+// eq: OUT = ( ( (IN - k) / d ) ^ GAMMA) * q
+//
+// Parameters:
+// in - Input brightness value (e.g., 0-255).
+// in_offset - Minimum input value (k in the equation),
+// below which input is clamped.
+// in_max - Maximum input value (d + k in the equation).
+// gamma_exp - Gamma exponent (GAMMA in the equation).
+// out_max - Maximum output value (q in the equation).
+//
+// The transformation performed is:
+// OUT = ( ( (max(IN, in_offset) - in_offset) / (in_max - in_offset) ) ^
+// gamma_exp) * out_max
+//
+// This normalizes the input, applies gamma correction, and scales to the output
+// range.
static inline uint32_t gamma_correction(uint8_t in, uint8_t in_offset,
- uint8_t in_max, float gamma,
+ uint8_t in_max, float gamma_exp,
uint32_t out_max) {
float out;
out = (float)(MAX(in, in_offset) - in_offset) /
(in_max - in_offset); // Input normalization to <0;1>
- out = powf(out, gamma); // Gamma correction
+ out = powf(out, gamma_exp); // Gamma correction
out = out * out_max; // Output denormalization to <0;out_max>
return (uint32_t)out;
}
-bool backlight_init(backlight_action_t action) {
+bool backlight_init(backlight_action_t action, float gamma_exp) {
backlight_driver_t *drv = &g_backlight_driver;
if (drv->initialized) {
@@ -286,6 +305,9 @@ bool backlight_init(backlight_action_t action) {
drv->max_level = BACKLIGHT_MAX_LEVEL;
drv->requested_level = BACKLIGHT_MIN_LEVEL;
+ // Store gamma exponent
+ drv->gamma_exp = gamma_exp;
+
drv->initialized = true;
return true;
@@ -337,7 +359,7 @@ bool backlight_set(uint8_t val) {
// Perform gamma correction of the requested level
drv->requested_level_corrected =
gamma_correction(drv->requested_level_limited, INPUT_OFFSET,
- BACKLIGHT_MAX_LEVEL, GAMMA_CORRECTION, USTEPS_COUNT);
+ BACKLIGHT_MAX_LEVEL, drv->gamma_exp, USTEPS_COUNT);
// Calculate the mapping of requested level to steps (quotient)
drv->requested_step =
diff --git a/core/embed/io/display/ltdc_dsi/display_driver.c b/core/embed/io/display/ltdc_dsi/display_driver.c
index a37d7bd3..9b873089 100644
--- a/core/embed/io/display/ltdc_dsi/display_driver.c
+++ b/core/embed/io/display/ltdc_dsi/display_driver.c
@@ -353,7 +353,7 @@ bool display_init(display_content_mode_t mode) {
#endif
#ifdef USE_BACKLIGHT
- backlight_init(BACKLIGHT_RESET);
+ backlight_init(BACKLIGHT_RESET, GAMMA_EXP);
#endif
uint32_t fb_addr = display_fb_init();
diff --git a/core/embed/io/display/ltdc_dsi/display_internal.h b/core/embed/io/display/ltdc_dsi/display_internal.h
index e5db3f4a..dc486899 100644
--- a/core/embed/io/display/ltdc_dsi/display_internal.h
+++ b/core/embed/io/display/ltdc_dsi/display_internal.h
@@ -33,6 +33,12 @@
#include "panels/stm32u5a9j-dk/stm32u5a9j-dk.h"
#endif
+#define GAMMA_EXP_DEFAULT 1.0f
+
+#ifndef GAMMA_EXP
+#define GAMMA_EXP GAMMA_EXP_DEFAULT
+#endif
+
// Hardware requires physical frame buffer alignment
#ifdef USE_TRUSTZONE
#define PHYSICAL_FRAME_BUFFER_ALIGNMENT TZ_SRAM_ALIGNMENT
diff --git a/core/embed/io/display/ltdc_dsi/panels/lx250a2401a/lx250a2401a.h b/core/embed/io/display/ltdc_dsi/panels/lx250a2401a/lx250a2401a.h
index a32c03f4..9e36b0e5 100644
--- a/core/embed/io/display/ltdc_dsi/panels/lx250a2401a/lx250a2401a.h
+++ b/core/embed/io/display/ltdc_dsi/panels/lx250a2401a/lx250a2401a.h
@@ -45,6 +45,8 @@
#define PANEL_DSI_LANES DSI_TWO_DATA_LANES
#define PANEL_LTDC_PIXEL_FORMAT LTDC_PIXEL_FORMAT_ARGB8888
+#define GAMMA_EXP 2.2f
+
// Size of the physical frame buffer in bytes
//
// It's smaller than size of the virtual frame buffer
diff --git a/core/embed/io/display/st-7789/display_driver.c b/core/embed/io/display/st-7789/display_driver.c
index 3e1e5179..fd4b4792 100644
--- a/core/embed/io/display/st-7789/display_driver.c
+++ b/core/embed/io/display/st-7789/display_driver.c
@@ -71,7 +71,7 @@ bool display_init(display_content_mode_t mode) {
display_io_init_fmc();
display_panel_init();
display_panel_set_little_endian();
- backlight_init(BACKLIGHT_RESET);
+ backlight_init(BACKLIGHT_RESET, GAMMA_EXP);
} else {
// Reinitialize FMC to set correct timing
// We have to do this in reinit because boardloader is fixed.
@@ -80,7 +80,7 @@ bool display_init(display_content_mode_t mode) {
// Important for model T as this is not set in boardloader
display_panel_set_little_endian();
display_panel_reinit();
- backlight_init(BACKLIGHT_RETAIN);
+ backlight_init(BACKLIGHT_RETAIN, GAMMA_EXP);
}
#ifdef FRAMEBUFFER
diff --git a/core/embed/io/display/st-7789/display_internal.h b/core/embed/io/display/st-7789/display_internal.h
index b8e94455..929090a5 100644
--- a/core/embed/io/display/st-7789/display_internal.h
+++ b/core/embed/io/display/st-7789/display_internal.h
@@ -10,6 +10,12 @@
#endif // FRAMEBUFFER
+#define GAMMA_EXP_DEFAULT 1.0f
+
+#ifndef GAMMA_EXP
+#define GAMMA_EXP GAMMA_EXP_DEFAULT
+#endif
+
// Display driver state
typedef struct {
// Set if the driver is initialized
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.