feat(core): add compile time switch to disable power manager thermal control.
What changed, and why it matters
This commit adds a compile-time switch that lets developers turn off the battery-charging temperature limiter in Trezor's STM32U5 power manager. By default the thermal control stays enabled, so normal builds are unchanged. The change itself is a feature flag, not a fix for an active bug or vulnerability, and there is no claim that it addresses a security issue.
Treat as a routine firmware feature. If this flag is used in production builds, ensure it is accompanied by a documented safety/thermal review and that the default remains enabled unless an alternative thermal management strategy is in place. No immediate security response is indicated by the commit itself.
Security signals we found
Compile-time switch can disable battery thermal throttling
Default configuration leaves thermal control enabled
No commit message or vendor reference describes this as a security fix
Disabling thermal control could, in a custom/non-default build, allow charging at higher temperatures than the hardware design intended
Evidence from the diff
The patch introduces PM_ENABLE_TEMP_CONTROL around the temperature controller logic in the STM32U5 power manager. When the macro is defined (default), behavior is identical to before. When commented out, pm_temperature_controller() and its data structures are compiled out, and the charging current is no longer reduced based on NTC temperature bands. The commit message is a feature addition with [no changelog] and no security framing.
Changed components
core/embed/sys/power_manager/stm32u5/power_manager.ccore/embed/sys/power_manager/stm32u5/power_manager_internal.hcore/embed/sys/power_manager/stm32u5/power_monitoring.cInspect captured patch +22 / −0
diff --git a/core/embed/sys/power_manager/stm32u5/power_manager.c b/core/embed/sys/power_manager/stm32u5/power_manager.c
index 9b69f415c..368e7b3d1 100644
--- a/core/embed/sys/power_manager/stm32u5/power_manager.c
+++ b/core/embed/sys/power_manager/stm32u5/power_manager.c
@@ -160,7 +160,10 @@ pm_status_t pm_init(bool inherit_state) {
// Set default SOC target and max charging current limit
drv->soc_target = 100;
drv->i_chg_max_limit_ma = PM_BATTERY_CHARGING_CURRENT_MAX;
+
+#ifdef PM_ENABLE_TEMP_CONTROL
drv->i_chg_temp_limit_ma = PM_BATTERY_CHARGING_CURRENT_MAX;
+#endif
// Fuel gauge SoC available, set fuel_gauge initialized.
drv->fuel_gauge_initialized = true;
diff --git a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h
index ccc75fceb..9cb6afd34 100644
--- a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h
+++ b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h
@@ -52,6 +52,10 @@
#define PM_AUTO_HIBERNATE_TIMEOUT_S (2 * 60 * 60) // 2 hours
#define PM_STABILIZATION_TIMEOUT_MS 2000
+
+// Thermal controller switch, comment out to disable the thermal controller
+#define PM_ENABLE_TEMP_CONTROL
+
// Temperature controller parameters
#define PM_TEMP_CONTROL_IDLE_PERIOD_MS 2 * 60 * 1000 // 2 minutes
#define PM_TEMP_CONTROL_BAND_1_MAX_TEMP 39.0f
@@ -97,9 +101,11 @@ typedef struct {
uint16_t i_chg_target_ma;
uint16_t i_chg_max_limit_ma;
+#ifdef PM_ENABLE_TEMP_CONTROL
// Temp controller
uint32_t temp_control_timeout;
uint16_t i_chg_temp_limit_ma;
+#endif
// Power source hardware state
pmic_report_t pmic_data;
diff --git a/core/embed/sys/power_manager/stm32u5/power_monitoring.c b/core/embed/sys/power_manager/stm32u5/power_monitoring.c
index df7b5d696..170e48b11 100644
--- a/core/embed/sys/power_manager/stm32u5/power_monitoring.c
+++ b/core/embed/sys/power_manager/stm32u5/power_monitoring.c
@@ -29,10 +29,15 @@
#include "../stwlc38/stwlc38.h"
#include "power_manager_internal.h"
+#ifdef PM_ENABLE_TEMP_CONTROL
static void pm_temperature_controller(pm_driver_t* drv);
+#endif
+
static void pm_battery_sampling(float vbat, float ibat, float ntc_temp);
static void pm_parse_power_source_state(pm_driver_t* drv);
+#ifdef PM_ENABLE_TEMP_CONTROL
+
// Temperature controller LUT
static const struct {
float max_temp;
@@ -44,6 +49,8 @@ static const struct {
{PM_TEMP_CONTROL_BAND_4_MAX_TEMP, 0.3},
};
+#endif
+
void pm_monitor_power_sources(void) {
// Periodically called timer to request PMIC measurements. PMIC will call
// pm_pmic_data_ready() callback when the measurements are ready.
@@ -168,7 +175,9 @@ void pm_charging_controller(pm_driver_t* drv) {
drv->i_chg_target_ma = drv->i_chg_max_limit_ma;
}
+#ifdef PM_ENABLE_TEMP_CONTROL
pm_temperature_controller(drv);
+#endif
if (drv->soc_target == 100) {
drv->soc_target_reached = false;
@@ -222,6 +231,8 @@ void pm_charging_controller(pm_driver_t* drv) {
}
}
+#ifdef PM_ENABLE_TEMP_CONTROL
+
static void pm_temperature_controller(pm_driver_t* drv) {
if (ticks_expired(drv->temp_control_timeout)) {
uint16_t i_chg_temp_limit_ma = 0;
@@ -249,6 +260,8 @@ static void pm_temperature_controller(pm_driver_t* drv) {
}
}
+#endif
+
static void pm_battery_sampling(float vbat, float ibat, float ntc_temp) {
pm_driver_t* drv = &g_pm;
Why this scored 19/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.