refactor(core): split and move suspend module into io and sec layers
What changed, and why it matters
This commit is a code reorganization (refactor) that moves the suspend/resume functionality from one part of the codebase to another. It splits the suspend module into an I/O layer and a security layer, updates include paths, and adjusts build configuration files. There is no indication of a security fix or vulnerability being addressed.
No security action required. Treat as routine maintenance/refactoring. Standard code review and regression testing for suspend/resume behavior on affected hardware revisions is sufficient.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors the suspend subsystem in Trezor firmware. It moves headers and source files from core/embed/sys/suspend/ to core/embed/io/suspend/ and core/embed/sec/suspend/. The public API (system_suspend, wakeup_flags_*) remains in io/suspend.h, while low-level CPU suspend and secure driver suspend/resume are moved to sec/suspend_io.h and implemented in secure mode. All consumers are updated to include the new headers, and SCons build scripts are updated to reference the new paths. The functional logic is preserved with only minor structural changes.
Changed components
core/embed/io/suspendcore/embed/sec/suspendcore/embed/sys/suspend (removed)core/embed/io/button/stm32/button.ccore/embed/io/nrf/stm32u5/nrf.ccore/embed/io/power_managercore/embed/io/usb/stm32/usb_class_hid.ccore/embed/io/usb/stm32/usb_class_vcp.ccore/embed/io/usb/stm32/usb_class_webusb.ccore/embed/rust/build.rscore/embed/rust/trezorhal.hcore/embed/sys/smcall/stm32/smcall_dispatch.ccore/embed/sys/smcall/stm32/smcall_stubs.ccore/embed/sys/time/stm32u5/rtc.ccore/site_scons/models/T3W1Inspect captured patch +611 / −528
diff --git a/core/embed/io/button/stm32/button.c b/core/embed/io/button/stm32/button.c
index a6057597..2fcbec7c 100644
--- a/core/embed/io/button/stm32/button.c
+++ b/core/embed/io/button/stm32/button.c
@@ -28,7 +28,7 @@
#include "../button_poll.h"
#ifdef USE_SUSPEND
-#include <sys/suspend.h>
+#include <io/suspend.h>
#endif
#ifdef KERNEL_MODE
diff --git a/core/embed/io/nrf/stm32u5/nrf.c b/core/embed/io/nrf/stm32u5/nrf.c
index b4b0aaab..038704a2 100644
--- a/core/embed/io/nrf/stm32u5/nrf.c
+++ b/core/embed/io/nrf/stm32u5/nrf.c
@@ -32,7 +32,7 @@
#include <sys/systimer.h>
#ifdef USE_SUSPEND
-#include <sys/suspend.h>
+#include <io/suspend.h>
#endif
#include "../crc8.h"
diff --git a/core/embed/io/power_manager/inc/io/power_manager.h b/core/embed/io/power_manager/inc/io/power_manager.h
index 6d79c7f8..8a169b62 100644
--- a/core/embed/io/power_manager/inc/io/power_manager.h
+++ b/core/embed/io/power_manager/inc/io/power_manager.h
@@ -21,7 +21,7 @@
#include <trezor_types.h>
-#include <sys/suspend.h>
+#include <io/suspend.h>
/* power manager status codes */
typedef enum {
diff --git a/core/embed/io/power_manager/npm1300/npm1300.c b/core/embed/io/power_manager/npm1300/npm1300.c
index 689142aa..c3a72fc7 100644
--- a/core/embed/io/power_manager/npm1300/npm1300.c
+++ b/core/embed/io/power_manager/npm1300/npm1300.c
@@ -29,7 +29,7 @@
#include <sys/systimer.h>
#ifdef USE_SUSPEND
-#include <sys/suspend.h>
+#include <io/suspend.h>
#endif
#include "npm1300_defs.h"
diff --git a/core/embed/io/power_manager/stm32u5/power_manager.c b/core/embed/io/power_manager/stm32u5/power_manager.c
index 2fb01937..ea500c33 100644
--- a/core/embed/io/power_manager/stm32u5/power_manager.c
+++ b/core/embed/io/power_manager/stm32u5/power_manager.c
@@ -21,9 +21,9 @@
#include <trezor_rtl.h>
#include <io/pmic.h>
+#include <io/suspend.h>
#include <sec/backup_ram.h>
#include <sys/irq.h>
-#include <sys/suspend.h>
#include <sys/systick.h>
#include <sys/systimer.h>
diff --git a/core/embed/io/suspend/inc/io/suspend.h b/core/embed/io/suspend/inc/io/suspend.h
new file mode 100644
index 00000000..6f345a4f
--- /dev/null
+++ b/core/embed/io/suspend/inc/io/suspend.h
@@ -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/>.
+ */
+
+#pragma once
+
+#include <trezor_types.h>
+
+/** Set of wake-up flags */
+typedef uint16_t wakeup_flags_t;
+
+#define WAKEUP_FLAG_BUTTON (1 << 0) /** Button pressed */
+#define WAKEUP_FLAG_POWER (1 << 1) /** Power up */
+#define WAKEUP_FLAG_BLE (1 << 2) /** Bluetooth communication */
+#define WAKEUP_FLAG_NFC (1 << 3) /** NFC event */
+#define WAKEUP_FLAG_RTC (1 << 4) /** RTC wake-up timer */
+#define WAKEUP_FLAG_USB (1 << 5) /** USB WIRE communication */
+
+/**
+ * @brief Puts device into suspend mode (actually STOP2 mode on STM32U5)
+ *
+ * @return Return flags indicating the reason for wakeup
+ */
+wakeup_flags_t system_suspend(void);
+
+/**
+ * @brief Set wakeup flags
+ * @param flags Wakeup flags to set
+ */
+void wakeup_flags_set(wakeup_flags_t flags);
+
+/**
+ * @brief Reset wakeup flags
+ */
+void wakeup_flags_reset(void);
+
+/**
+ * @brief Get wakeup flags
+ * @param flags Pointer to store the current wakeup flags
+ */
+void wakeup_flags_get(wakeup_flags_t* flags);
diff --git a/core/embed/io/suspend/inc/io/suspend_io.h b/core/embed/io/suspend/inc/io/suspend_io.h
new file mode 100644
index 00000000..d63739dc
--- /dev/null
+++ b/core/embed/io/suspend/inc/io/suspend_io.h
@@ -0,0 +1,103 @@
+/*
+ * 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/>.
+ */
+
+#pragma once
+
+#ifdef USE_BLE
+#include <io/ble.h>
+#endif
+
+#ifdef USE_RGB_LED
+#include <io/rgb_led.h>
+#endif
+
+/**
+ * @brief Switches the CPU to STOP2 low-power mode.
+ *
+ * This function blocks until an interrupt wakes the CPU.
+ * Upon wake-up, it restores the system clock so the CPU can run at full speed.
+ */
+void suspend_cpu(void);
+
+/**
+ * @brief State of the drivers before entering a low-power mode
+ * used to restore them after wake-up.
+ */
+typedef struct {
+#ifdef USE_BACKLIGHT
+ /** Backlight level */
+ uint8_t backlight_level;
+#endif
+#ifdef USE_BLE
+ /** State of the ble driver */
+ ble_wakeup_params_t ble;
+#endif
+#ifdef USE_RGB_LED
+ /** State of the rgb_led driver */
+ rgb_led_wakeup_params_t rgb_led;
+#endif
+} power_save_wakeup_params_t;
+
+/**
+ * @brief Suspends I/O drivers.
+ *
+ * This function is called before the device enters a low-power state.
+ * It suspends I/O drivers to reduce power consumption.
+ *
+ * @param wakeup_params Pointer to a structure that will be filled with
+ * the state of the drivers before entering low-power mode.
+ */
+void suspend_drivers_phase1(power_save_wakeup_params_t *wakeup_params);
+
+/**
+ * @brief Suspends additional I/O drivers.
+ *
+ * This function is called after the device enters a low-power state.
+ * It suspends additional I/O drivers that were not suspended in phase 1.
+ */
+void suspend_drivers_phase2(void);
+
+/**
+ * @brief Resumes I/O drivers.
+ *
+ * This function is called when the device exits a low-power state.
+ * It resumes I/O drivers that were suspended before entering
+ * the low-power state.
+ *
+ * @param wakeup_params Pointer to a structure that contains the state of the
+ * drivers before entering low-power mode.
+ */
+void resume_drivers(const power_save_wakeup_params_t *wakeup_params);
+
+/**
+ * @brief Suspends secure peripherals.
+ *
+ * This function is called before the device enters a low-power state.
+ * It suspends secure peripherals to reduce power consumption.
+ */
+void suspend_secure_drivers(void);
+
+/**
+ * @brief Resumes secure peripherals.
+ *
+ * This function is called when the device exits a low-power state.
+ * It resumes secure peripherals that were suspended before entering
+ * the low-power state.
+ */
+void resume_secure_drivers(void);
diff --git a/core/embed/io/suspend/stm32u5/suspend.c b/core/embed/io/suspend/stm32u5/suspend.c
new file mode 100644
index 00000000..ca4ed821
--- /dev/null
+++ b/core/embed/io/suspend/stm32u5/suspend.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/>.
+ */
+#if defined(KERNEL_MODE) && !defined(SECMON)
+
+#include <trezor_bsp.h>
+#include <trezor_rtl.h>
+
+#include <io/suspend.h>
+#include <io/suspend_io.h>
+#include <sec/suspend_io.h>
+#include <sys/irq.h>
+
+#include <../../power_manager/stwlc38/stwlc38.h>
+#include <io/pmic.h>
+#include <io/power_manager.h>
+
+#ifdef USE_RGB_LED
+#include <io/rgb_led.h>
+#endif
+
+static wakeup_flags_t g_wakeup_flags = 0;
+
+static void background_tasks_suspend(void);
+static bool background_tasks_suspended(void);
+static void background_tasks_resume(void);
+
+void wakeup_flags_set(wakeup_flags_t flags) {
+ irq_key_t irq_key = irq_lock();
+ g_wakeup_flags |= flags;
+ irq_unlock(irq_key);
+}
+
+void wakeup_flags_reset(void) {
+ irq_key_t irq_key = irq_lock();
+ g_wakeup_flags = 0;
+ irq_unlock(irq_key);
+}
+
+void wakeup_flags_get(wakeup_flags_t* flags) {
+ irq_key_t irq_key = irq_lock();
+ *flags = g_wakeup_flags;
+ irq_unlock(irq_key);
+}
+
+wakeup_flags_t system_suspend(void) {
+ // Clear all wakeup flags. From this point, any wakeup event that
+ // sets a wakeup flag causes this function to return.
+ wakeup_flags_reset();
+
+ power_save_wakeup_params_t wakeup_params = {0};
+
+ // Deinitialize drivers that are not required in low-power charging phase
+ // (e.g., display, touch, haptic, etc.).
+ suspend_drivers_phase1(&wakeup_params);
+
+ wakeup_flags_t wakeup_flags = 0;
+ wakeup_flags_get(&wakeup_flags);
+
+ // If the device is requested to go in suspend, but the USB is connected,
+ // Keep in this loop until the external power got disconnected or the
+ // device is waked up. Also, if the battery is charging, the state is signaled
+ // with RGB LED charging effect.
+
+ bool charging_in_suspend = false;
+ do {
+#ifdef USE_RGB_LED
+ if (pm_is_charging()) {
+ charging_in_suspend = true;
+ if (!rgb_led_effect_ongoing()) {
+ rgb_led_effect_start(RGB_LED_EFFECT_CHARGING, 0);
+ }
+ } else {
+ charging_in_suspend = false;
+ rgb_led_effect_stop();
+ }
+#endif
+
+ __WFI();
+
+ wakeup_flags_get(&wakeup_flags);
+
+ } while ((pm_usb_is_connected() || charging_in_suspend) &&
+ (wakeup_flags == 0));
+
+ if (wakeup_flags == 0) {
+ // Deinitialize rest of the drivers before entering low-power mode
+ suspend_drivers_phase2();
+ }
+
+ // In the following loop, the system will attempt to enter low-power mode.
+ // Low-power mode may be exited for various reasons, but the loop will
+ // terminate only if a wakeup flag is set, indicating that user interaction
+ // is required or the user needs to be notified.
+
+ while (wakeup_flags == 0) {
+ // Notify state machines running in the interrupt context about the
+ // impending low-power mode. They should complete any pending operations
+ // and avoid starting new ones.
+ background_tasks_suspend();
+
+ // Wait until all state machines are idle and the system is ready to enter
+ // low-power mode. This loop also exits if any wakeup flag is set
+ // (e.g., due to a button press).
+ do {
+ __WFI();
+
+ // TODO: Implement a 5-second timeout to trigger a fatal error.
+
+ // Check for wakeup flags again
+ wakeup_flags_get(&wakeup_flags);
+
+ } while (!background_tasks_suspended() && (wakeup_flags == 0));
+
+ if (wakeup_flags == 0) {
+ // Enter low-power mode
+ suspend_cpu();
+ }
+
+ // Resume state machines running in the interrupt context
+ background_tasks_resume();
+
+ // Some wakeup flags may be set in interrupts right after CPU wakes up, and
+ // some may be set in the background tasks resume routine. Read them here
+ // to wake up immediately if any are set.
+ wakeup_flags_get(&wakeup_flags);
+ }
+
+ // Reinitialize all drivers that were stopped earlier
+ resume_drivers(&wakeup_params);
+
+ return wakeup_flags;
+}
+
+static void background_tasks_suspend(void) {
+ pm_driver_suspend();
+ pmic_suspend();
+ stwlc38_suspend();
+}
+
+static bool background_tasks_suspended(void) {
+ return pmic_is_suspended() && stwlc38_is_suspended() &&
+ pm_driver_is_suspended();
+}
+
+static void background_tasks_resume(void) {
+ stwlc38_resume();
+ pmic_resume();
+ pm_driver_resume();
+}
+
+#endif // defined(KERNEL_MODE) && !defined(SECMON)
diff --git a/core/embed/io/suspend/stm32u5/suspend_io.c b/core/embed/io/suspend/stm32u5/suspend_io.c
new file mode 100644
index 00000000..b5bb78da
--- /dev/null
+++ b/core/embed/io/suspend/stm32u5/suspend_io.c
@@ -0,0 +1,126 @@
+/*
+ * 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/>.
+ */
+#ifdef KERNEL_MODE
+
+#include <trezor_bsp.h>
+#include <trezor_rtl.h>
+
+#include <io/suspend_io.h>
+#include <sec/suspend_io.h>
+#include <sys/irq.h>
+
+#ifdef USE_BLE
+#include <io/ble.h>
+#endif
+
+#ifdef USE_DISPLAY
+#include <io/display.h>
+#endif
+
+#ifdef USE_HAPTIC
+#include <io/haptic.h>
+#endif
+
+#ifdef USE_OPTIGA
+#include <sec/optiga_init.h>
+#endif
+
+#ifdef USE_RGB_LED
+#include <io/rgb_led.h>
+#endif
+
+#ifdef USE_TOUCH
+#include <io/touch.h>
+#endif
+
+#ifdef USE_USB
+#include <io/usb.h>
+#endif
+
+void suspend_drivers_phase1(power_save_wakeup_params_t *wakeup_params) {
+ suspend_secure_drivers();
+
+#ifdef USE_OPTIGA
+ // Optiga has to be suspended from kernel, since the suspend routine needs
+ // to access RTC scheduler which is not available in secure mode.
+ optiga_suspend();
+#endif
+
+#ifdef USE_HAPTIC
+ haptic_deinit();
+#endif
+#ifdef USE_RGB_LED
+ // Just store the wakeup params and turn off the LED
+ rgb_led_set_wakeup_params(&wakeup_params->rgb_led);
+ rgb_led_set_color(RGBLED_OFF);
+#endif
+#ifdef USE_TOUCH
+ touch_deinit();
+#endif
+#ifdef USE_BLE
+ ble_suspend(&wakeup_params->ble);
+#endif
+#ifdef USE_DISPLAY
+ wakeup_params->backlight_level = display_get_backlight();
+ display_deinit(DISPLAY_RESET_CONTENT);
+#endif
+}
+
+void suspend_drivers_phase2(void) {
+#ifdef USE_USB
+ usb_stop();
+#endif
+
+#ifdef USE_RGB_LED
+ rgb_led_suspend();
+#endif
+}
+
+void resume_drivers(const power_save_wakeup_params_t *wakeup_params) {
+#ifdef USE_DISPLAY
+ // Reinitialize all drivers that were stopped earlier
+ display_init(DISPLAY_RESET_CONTENT);
+ display_set_backlight(wakeup_params->backlight_level);
+#endif
+#ifdef USE_TOUCH
+ touch_init();
+#endif
+#ifdef USE_HAPTIC
+ ts_t status = haptic_init();
+ ensure_ok(status, "haptic driver initialization failed");
+#endif
+#ifdef USE_RGB_LED
+ rgb_led_resume(&wakeup_params->rgb_led);
+#endif
+#ifdef USE_USB
+ usb_start(NULL);
+#endif
+#ifdef USE_BLE
+ ble_resume(&wakeup_params->ble);
+#endif
+
+ resume_secure_drivers();
+
+#ifdef USE_OPTIGA
+ // Optiga kernel part of resume routine
+ optiga_resume();
+#endif
+}
+
+#endif // KERNEL_MODE
diff --git a/core/embed/io/usb/stm32/usb_class_hid.c b/core/embed/io/usb/stm32/usb_class_hid.c
index c9c026f2..0fa5fd1b 100644
--- a/core/embed/io/usb/stm32/usb_class_hid.c
+++ b/core/embed/io/usb/stm32/usb_class_hid.c
@@ -26,7 +26,7 @@
#include <sys/sysevent_source.h>
#ifdef USE_SUSPEND
-#include <sys/suspend.h>
+#include <io/suspend.h>
#endif
#include "usb_internal.h"
diff --git a/core/embed/io/usb/stm32/usb_class_vcp.c b/core/embed/io/usb/stm32/usb_class_vcp.c
index 6728a50c..e32bd6e6 100644
--- a/core/embed/io/usb/stm32/usb_class_vcp.c
+++ b/core/embed/io/usb/stm32/usb_class_vcp.c
@@ -26,7 +26,7 @@
#include <sys/sysevent_source.h>
#ifdef USE_SUSPEND
-#include <sys/suspend.h>
+#include <io/suspend.h>
#endif
#include "usb_internal.h"
diff --git a/core/embed/io/usb/stm32/usb_class_webusb.c b/core/embed/io/usb/stm32/usb_class_webusb.c
index e6569438..ee0699e4 100644
--- a/core/embed/io/usb/stm32/usb_class_webusb.c
+++ b/core/embed/io/usb/stm32/usb_class_webusb.c
@@ -26,7 +26,7 @@
#include <sys/sysevent_source.h>
#ifdef USE_SUSPEND
-#include <sys/suspend.h>
+#include <io/suspend.h>
#endif
#include "usb_internal.h"
diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs
index 31f3a138..2bbe0038 100644
--- a/core/embed/rust/build.rs
+++ b/core/embed/rust/build.rs
@@ -45,6 +45,7 @@ const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[
"-I../io/touch/inc",
"-I../io/power_manager/inc",
"-I../io/rgb_led/inc",
+ "-I../io/suspend/inc",
"-I../io/translations/inc",
"-I../io/usb/inc",
"-I../sec/storage/inc",
@@ -52,7 +53,6 @@ const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[
"-I../sys/inc",
"-I../sys/time/inc",
"-I../sys/task/inc",
- "-I../sys/suspend/inc",
"-I../sys/irq/inc",
"-I../sys/flash/inc",
"-I../models",
diff --git a/core/embed/rust/trezorhal.h b/core/embed/rust/trezorhal.h
index c5072e9a..36b2a585 100644
--- a/core/embed/rust/trezorhal.h
+++ b/core/embed/rust/trezorhal.h
@@ -48,7 +48,7 @@
#endif
#ifdef USE_SUSPEND
-#include <sys/suspend.h>
+#include <io/suspend.h>
#endif
#ifdef USE_STORAGE
diff --git a/core/embed/sec/suspend/inc/sec/suspend_io.h b/core/embed/sec/suspend/inc/sec/suspend_io.h
new file mode 100644
index 00000000..6e373b6f
--- /dev/null
+++ b/core/embed/sec/suspend/inc/sec/suspend_io.h
@@ -0,0 +1,45 @@
+/*
+ * 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/>.
+ */
+
+#pragma once
+
+/**
+ * @brief Switches the CPU to STOP2 low-power mode.
+ *
+ * This function blocks until an interrupt wakes the CPU.
+ * Upon wake-up, it restores the system clock so the CPU can run at full speed.
+ */
+void suspend_cpu(void);
+
+/**
+ * @brief Suspends secure peripherals.
+ *
+ * This function is called before the device enters a low-power state.
+ * It suspends secure peripherals to reduce power consumption.
+ */
+void suspend_secure_drivers(void);
+
+/**
+ * @brief Resumes secure peripherals.
+ *
+ * This function is called when the device exits a low-power state.
+ * It resumes secure peripherals that were suspended before entering
+ * the low-power state.
+ */
+void resume_secure_drivers(void);
diff --git a/core/embed/sec/suspend/stm32u5/suspend_io.c b/core/embed/sec/suspend/stm32u5/suspend_io.c
new file mode 100644
index 00000000..75969810
--- /dev/null
+++ b/core/embed/sec/suspend/stm32u5/suspend_io.c
@@ -0,0 +1,79 @@
+/*
+ * 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/>.
+ */
+
+#ifdef SECURE_MODE
+
+#include <trezor_bsp.h>
+#include <trezor_rtl.h>
+
+#include <sec/suspend_io.h>
+#include <sys/irq.h>
+
+#ifdef USE_STORAGE_HWKEY
+#include <sec/secure_aes.h>
+#endif
+
+#ifdef USE_TROPIC
+#include <sec/tropic.h>
+#endif
+
+void suspend_cpu(void) {
+ // Disable interrupts by setting PRIMASK to 1.
+ //
+ // The system can wake up, but interrupts will not be processed until
+ // PRIMASK is cleared again. This is necessary to restore the system clock
+ // immediately after exiting STOP2 mode.
+
+ irq_key_t irq_key = irq_lock();
+
+ // The PWR clock is disabled after system initialization.
+ // Re-enable it before writing to PWR registers.
+ __HAL_RCC_PWR_CLK_ENABLE();
+
+ // Enter STOP2 low-power mode
+ HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
+
+ // Disable PWR clock after use
+ __HAL_RCC_PWR_CLK_DISABLE();
+
+ // Recover system clock
+ SystemInit();
+
+ irq_unlock(irq_key);
+}
+
+void suspend_secure_drivers() {
+#ifdef USE_STORAGE_HWKEY
+ secure_aes_deinit();
+#endif
+#ifdef USE_TROPIC
+ tropic_deinit();
+#endif
+}
+
+void resume_secure_drivers() {
+#ifdef USE_STORAGE_HWKEY
+ secure_aes_init();
+#endif
+#ifdef USE_TROPIC
+ tropic_init();
+#endif
+}
+
+#endif // SECURE_MODE
diff --git a/core/embed/sys/smcall/stm32/smcall_dispatch.c b/core/embed/sys/smcall/stm32/smcall_dispatch.c
index 5c6c11c9..4a87cc94 100644
--- a/core/embed/sys/smcall/stm32/smcall_dispatch.c
+++ b/core/embed/sys/smcall/stm32/smcall_dispatch.c
@@ -43,7 +43,7 @@
#endif
#ifdef USE_SUSPEND
-#include <sys/suspend_io.h>
+#include <sec/suspend_io.h>
#endif
#include <sec/boot_image.h>
diff --git a/core/embed/sys/smcall/stm32/smcall_stubs.c b/core/embed/sys/smcall/stm32/smcall_stubs.c
index 4285e791..f0593c92 100644
--- a/core/embed/sys/smcall/stm32/smcall_stubs.c
+++ b/core/embed/sys/smcall/stm32/smcall_stubs.c
@@ -109,7 +109,7 @@ void reboot_with_rsod(const systask_postmortem_t *pminfo) {
#ifdef USE_SUSPEND
-#include <sys/suspend_io.h>
+#include <sec/suspend_io.h>
void suspend_cpu(void) { smcall_invoke0(SMCALL_SUSPEND_CPU); }
diff --git a/core/embed/sys/suspend/inc/sys/suspend.h b/core/embed/sys/suspend/inc/sys/suspend.h
deleted file mode 100644
index 6f345a4f..00000000
--- a/core/embed/sys/suspend/inc/sys/suspend.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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/>.
- */
-
-#pragma once
-
-#include <trezor_types.h>
-
-/** Set of wake-up flags */
-typedef uint16_t wakeup_flags_t;
-
-#define WAKEUP_FLAG_BUTTON (1 << 0) /** Button pressed */
-#define WAKEUP_FLAG_POWER (1 << 1) /** Power up */
-#define WAKEUP_FLAG_BLE (1 << 2) /** Bluetooth communication */
-#define WAKEUP_FLAG_NFC (1 << 3) /** NFC event */
-#define WAKEUP_FLAG_RTC (1 << 4) /** RTC wake-up timer */
-#define WAKEUP_FLAG_USB (1 << 5) /** USB WIRE communication */
-
-/**
- * @brief Puts device into suspend mode (actually STOP2 mode on STM32U5)
- *
- * @return Return flags indicating the reason for wakeup
- */
-wakeup_flags_t system_suspend(void);
-
-/**
- * @brief Set wakeup flags
- * @param flags Wakeup flags to set
- */
-void wakeup_flags_set(wakeup_flags_t flags);
-
-/**
- * @brief Reset wakeup flags
- */
-void wakeup_flags_reset(void);
-
-/**
- * @brief Get wakeup flags
- * @param flags Pointer to store the current wakeup flags
- */
-void wakeup_flags_get(wakeup_flags_t* flags);
diff --git a/core/embed/sys/suspend/inc/sys/suspend_io.h b/core/embed/sys/suspend/inc/sys/suspend_io.h
deleted file mode 100644
index d63739dc..00000000
--- a/core/embed/sys/suspend/inc/sys/suspend_io.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * 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/>.
- */
-
-#pragma once
-
-#ifdef USE_BLE
-#include <io/ble.h>
-#endif
-
-#ifdef USE_RGB_LED
-#include <io/rgb_led.h>
-#endif
-
-/**
- * @brief Switches the CPU to STOP2 low-power mode.
- *
- * This function blocks until an interrupt wakes the CPU.
- * Upon wake-up, it restores the system clock so the CPU can run at full speed.
- */
-void suspend_cpu(void);
-
-/**
- * @brief State of the drivers before entering a low-power mode
- * used to restore them after wake-up.
- */
-typedef struct {
-#ifdef USE_BACKLIGHT
- /** Backlight level */
- uint8_t backlight_level;
-#endif
-#ifdef USE_BLE
- /** State of the ble driver */
- ble_wakeup_params_t ble;
-#endif
-#ifdef USE_RGB_LED
- /** State of the rgb_led driver */
- rgb_led_wakeup_params_t rgb_led;
-#endif
-} power_save_wakeup_params_t;
-
-/**
- * @brief Suspends I/O drivers.
- *
- * This function is called before the device enters a low-power state.
- * It suspends I/O drivers to reduce power consumption.
- *
- * @param wakeup_params Pointer to a structure that will be filled with
- * the state of the drivers before entering low-power mode.
- */
-void suspend_drivers_phase1(power_save_wakeup_params_t *wakeup_params);
-
-/**
- * @brief Suspends additional I/O drivers.
- *
- * This function is called after the device enters a low-power state.
- * It suspends additional I/O drivers that were not suspended in phase 1.
- */
-void suspend_drivers_phase2(void);
-
-/**
- * @brief Resumes I/O drivers.
- *
- * This function is called when the device exits a low-power state.
- * It resumes I/O drivers that were suspended before entering
- * the low-power state.
- *
- * @param wakeup_params Pointer to a structure that contains the state of the
- * drivers before entering low-power mode.
- */
-void resume_drivers(const power_save_wakeup_params_t *wakeup_params);
-
-/**
- * @brief Suspends secure peripherals.
- *
- * This function is called before the device enters a low-power state.
- * It suspends secure peripherals to reduce power consumption.
- */
-void suspend_secure_drivers(void);
-
-/**
- * @brief Resumes secure peripherals.
- *
- * This function is called when the device exits a low-power state.
- * It resumes secure peripherals that were suspended before entering
- * the low-power state.
- */
-void resume_secure_drivers(void);
diff --git a/core/embed/sys/suspend/stm32u5/suspend.c b/core/embed/sys/suspend/stm32u5/suspend.c
deleted file mode 100644
index 1dc5ba38..00000000
--- a/core/embed/sys/suspend/stm32u5/suspend.c
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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/>.
- */
-#if defined(KERNEL_MODE) && !defined(SECMON)
-
-#include <trezor_bsp.h>
-#include <trezor_rtl.h>
-
-#include <sys/irq.h>
-#include <sys/suspend.h>
-#include <sys/suspend_io.h>
-
-#include <../../power_manager/stwlc38/stwlc38.h>
-#include <io/pmic.h>
-#include <io/power_manager.h>
-
-#ifdef USE_RGB_LED
-#include <io/rgb_led.h>
-#endif
-
-static wakeup_flags_t g_wakeup_flags = 0;
-
-static void background_tasks_suspend(void);
-static bool background_tasks_suspended(void);
-static void background_tasks_resume(void);
-
-void wakeup_flags_set(wakeup_flags_t flags) {
- irq_key_t irq_key = irq_lock();
- g_wakeup_flags |= flags;
- irq_unlock(irq_key);
-}
-
-void wakeup_flags_reset(void) {
- irq_key_t irq_key = irq_lock();
- g_wakeup_flags = 0;
- irq_unlock(irq_key);
-}
-
-void wakeup_flags_get(wakeup_flags_t* flags) {
- irq_key_t irq_key = irq_lock();
- *flags = g_wakeup_flags;
- irq_unlock(irq_key);
-}
-
-wakeup_flags_t system_suspend(void) {
- // Clear all wakeup flags. From this point, any wakeup event that
- // sets a wakeup flag causes this function to return.
- wakeup_flags_reset();
-
- power_save_wakeup_params_t wakeup_params = {0};
-
- // Deinitialize drivers that are not required in low-power charging phase
- // (e.g., display, touch, haptic, etc.).
- suspend_drivers_phase1(&wakeup_params);
-
- wakeup_flags_t wakeup_flags = 0;
- wakeup_flags_get(&wakeup_flags);
-
- // If the device is requested to go in suspend, but the USB is connected,
- // Keep in this loop until the external power got disconnected or the
- // device is waked up. Also, if the battery is charging, the state is signaled
- // with RGB LED charging effect.
-
- bool charging_in_suspend = false;
- do {
-#ifdef USE_RGB_LED
- if (pm_is_charging()) {
- charging_in_suspend = true;
- if (!rgb_led_effect_ongoing()) {
- rgb_led_effect_start(RGB_LED_EFFECT_CHARGING, 0);
- }
- } else {
- charging_in_suspend = false;
- rgb_led_effect_stop();
- }
-#endif
-
- __WFI();
-
- wakeup_flags_get(&wakeup_flags);
-
- } while ((pm_usb_is_connected() || charging_in_suspend) &&
- (wakeup_flags == 0));
-
- if (wakeup_flags == 0) {
- // Deinitialize rest of the drivers before entering low-power mode
- suspend_drivers_phase2();
- }
-
- // In the following loop, the system will attempt to enter low-power mode.
- // Low-power mode may be exited for various reasons, but the loop will
- // terminate only if a wakeup flag is set, indicating that user interaction
- // is required or the user needs to be notified.
-
- while (wakeup_flags == 0) {
- // Notify state machines running in the interrupt context about the
- // impending low-power mode. They should complete any pending operations
- // and avoid starting new ones.
- background_tasks_suspend();
-
- // Wait until all state machines are idle and the system is ready to enter
- // low-power mode. This loop also exits if any wakeup flag is set
- // (e.g., due to a button press).
- do {
- __WFI();
-
- // TODO: Implement a 5-second timeout to trigger a fatal error.
-
- // Check for wakeup flags again
- wakeup_flags_get(&wakeup_flags);
-
- } while (!background_tasks_suspended() && (wakeup_flags == 0));
-
- if (wakeup_flags == 0) {
- // Enter low-power mode
- suspend_cpu();
- }
-
- // Resume state machines running in the interrupt context
- background_tasks_resume();
-
- // Some wakeup flags may be set in interrupts right after CPU wakes up, and
- // some may be set in the background tasks resume routine. Read them here
- // to wake up immediately if any are set.
- wakeup_flags_get(&wakeup_flags);
- }
-
- // Reinitialize all drivers that were stopped earlier
- resume_drivers(&wakeup_params);
-
- return wakeup_flags;
-}
-
-static void background_tasks_suspend(void) {
- pm_driver_suspend();
- pmic_suspend();
- stwlc38_suspend();
-}
-
-static bool background_tasks_suspended(void) {
- return pmic_is_suspended() && stwlc38_is_suspended() &&
- pm_driver_is_suspended();
-}
-
-static void background_tasks_resume(void) {
- stwlc38_resume();
- pmic_resume();
- pm_driver_resume();
-}
-
-#endif // defined(KERNEL_MODE) && !defined(SECMON)
diff --git a/core/embed/sys/suspend/stm32u5/suspend_io.c b/core/embed/sys/suspend/stm32u5/suspend_io.c
deleted file mode 100644
index 9e0734c5..00000000
--- a/core/embed/sys/suspend/stm32u5/suspend_io.c
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * 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/>.
- */
-#ifdef KERNEL_MODE
-
-#include <trezor_bsp.h>
-#include <trezor_rtl.h>
-
-#include <sys/irq.h>
-#include <sys/suspend_io.h>
-#include <sys/systick.h>
-
-#ifdef USE_BLE
-#include <io/ble.h>
-#endif
-
-#ifdef USE_DISPLAY
-#include <io/display.h>
-#endif
-
-#ifdef USE_HAPTIC
-#include <io/haptic.h>
-#endif
-
-#ifdef USE_OPTIGA
-#include <sec/optiga_init.h>
-#endif
-
-#ifdef USE_RGB_LED
-#include <io/rgb_led.h>
-#endif
-
-#ifdef USE_STORAGE_HWKEY
-#include <sec/secure_aes.h>
-#endif
-
-#ifdef USE_TOUCH
-#include <io/touch.h>
-#endif
-
-#ifdef USE_TROPIC
-#include <sec/tropic.h>
-#endif
-
-#ifdef USE_USB
-#include <io/usb.h>
-#endif
-
-#ifdef SECURE_MODE
-void suspend_cpu(void) {
- // Disable interrupts by setting PRIMASK to 1.
- //
- // The system can wake up, but interrupts will not be processed until
- // PRIMASK is cleared again. This is necessary to restore the system clock
- // immediately after exiting STOP2 mode.
-
- irq_key_t irq_key = irq_lock();
-
- // The PWR clock is disabled after system initialization.
- // Re-enable it before writing to PWR registers.
- __HAL_RCC_PWR_CLK_ENABLE();
-
- // Enter STOP2 low-power mode
- HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
-
- // Disable PWR clock after use
- __HAL_RCC_PWR_CLK_DISABLE();
-
- // Recover system clock
- SystemInit();
-
- irq_unlock(irq_key);
-}
-
-void suspend_secure_drivers() {
-#ifdef USE_STORAGE_HWKEY
- secure_aes_deinit();
-#endif
-#ifdef USE_TROPIC
- tropic_deinit();
-#endif
-}
-
-void resume_secure_drivers() {
-#ifdef USE_STORAGE_HWKEY
- secure_aes_init();
-#endif
-#ifdef USE_TROPIC
- tropic_init();
-#endif
-}
-
-#endif // SECURE_MODE
-
-void suspend_drivers_phase1(power_save_wakeup_params_t *wakeup_params) {
- suspend_secure_drivers();
-
-#ifdef USE_OPTIGA
- // Optiga has to be suspended from kernel, since the suspend routine needs
- // to access RTC scheduler which is not available in secure mode.
- optiga_suspend();
-#endif
-
-#ifdef USE_HAPTIC
- haptic_deinit();
-#endif
-#ifdef USE_RGB_LED
- // Just store the wakeup params and turn off the LED
- rgb_led_set_wakeup_params(&wakeup_params->rgb_led);
- rgb_led_set_color(RGBLED_OFF);
-#endif
-#ifdef USE_TOUCH
- touch_deinit();
-#endif
-#ifdef USE_BLE
- ble_suspend(&wakeup_params->ble);
-#endif
-#ifdef USE_DISPLAY
- wakeup_params->backlight_level = display_get_backlight();
- display_deinit(DISPLAY_RESET_CONTENT);
-#endif
-}
-
-void suspend_drivers_phase2(void) {
-#ifdef USE_USB
- usb_stop();
-#endif
-
-#ifdef USE_RGB_LED
- rgb_led_suspend();
-#endif
-}
-
-void resume_drivers(const power_save_wakeup_params_t *wakeup_params) {
-#ifdef USE_DISPLAY
- // Reinitialize all drivers that were stopped earlier
- display_init(DISPLAY_RESET_CONTENT);
- display_set_backlight(wakeup_params->backlight_level);
-#endif
-#ifdef USE_TOUCH
- touch_init();
-#endif
-#ifdef USE_HAPTIC
- ts_t status = haptic_init();
- ensure_ok(status, "haptic driver initialization failed");
-#endif
-#ifdef USE_RGB_LED
- rgb_led_resume(&wakeup_params->rgb_led);
-#endif
-#ifdef USE_USB
- usb_start(NULL);
-#endif
-#ifdef USE_BLE
- ble_resume(&wakeup_params->ble);
-#endif
-
- resume_secure_drivers();
-
-#ifdef USE_OPTIGA
- // Optiga kernel part of resume routine
- optiga_resume();
-#endif
-}
-
-#endif // KERNEL_MODE
diff --git a/core/embed/sys/time/stm32u5/rtc.c b/core/embed/sys/time/stm32u5/rtc.c
index e0481fbc..420cfee5 100644
--- a/core/embed/sys/time/stm32u5/rtc.c
+++ b/core/embed/sys/time/stm32u5/rtc.c
@@ -22,11 +22,11 @@
#include <trezor_bsp.h>
#include <trezor_rtl.h>
+#include <io/suspend.h>
#include <sys/irq.h>
#include <sys/mpu.h>
#include <sys/rtc.h>
#include <sys/rtc_scheduler.h>
-#include <sys/suspend.h>
// RTC driver structure
typedef struct {
diff --git a/core/site_scons/models/T3W1/emulator.py b/core/site_scons/models/T3W1/emulator.py
index 0164099e..eb3c8c0e 100644
--- a/core/site_scons/models/T3W1/emulator.py
+++ b/core/site_scons/models/T3W1/emulator.py
@@ -125,7 +125,7 @@ def configure(
paths += ["embed/io/power_manager/inc"]
features_available.append("power_manager")
- paths += ["embed/sys/suspend/inc"]
+ paths += ["embed/io/suspend/inc"]
features_available.append("backlight")
defines += [("USE_BACKLIGHT", "1")]
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
index 32956e66..33464876 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py
@@ -270,10 +270,14 @@ def configure(
if "suspend" in features_wanted:
sources += [
- "embed/sys/suspend/stm32u5/suspend.c",
- "embed/sys/suspend/stm32u5/suspend_io.c",
+ "embed/io/suspend/stm32u5/suspend.c",
+ "embed/io/suspend/stm32u5/suspend_io.c",
+ "embed/sec/suspend/stm32u5/suspend_io.c",
+ ]
+ paths += [
+ "embed/io/suspend/inc",
+ "embed/sec/suspend/inc",
]
- paths += ["embed/sys/suspend/inc"]
defines += [("USE_SUSPEND", "1")]
if "power_manager" in features_wanted:
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
index cd61e81b..9d10e9a7 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py
@@ -279,10 +279,14 @@ def configure(
if "suspend" in features_wanted:
sources += [
- "embed/sys/suspend/stm32u5/suspend.c",
- "embed/sys/suspend/stm32u5/suspend_io.c",
+ "embed/io/suspend/stm32u5/suspend.c",
+ "embed/io/suspend/stm32u5/suspend_io.c",
+ "embed/sec/suspend/stm32u5/suspend_io.c",
+ ]
+ paths += [
+ "embed/io/suspend/inc",
+ "embed/sec/suspend/inc",
]
- paths += ["embed/sys/suspend/inc"]
defines += [("USE_SUSPEND", "1")]
if "power_manager" in features_wanted:
diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
index 5200d78f..178fdf9d 100644
--- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py
+++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py
@@ -282,10 +282,14 @@ def configure(
if "suspend" in features_wanted:
sources += [
- "embed/sys/suspend/stm32u5/suspend.c",
- "embed/sys/suspend/stm32u5/suspend_io.c",
+ "embed/io/suspend/stm32u5/suspend.c",
+ "embed/io/suspend/stm32u5/suspend_io.c",
+ "embed/sec/suspend/stm32u5/suspend_io.c",
+ ]
+ paths += [
+ "embed/io/suspend/inc",
+ "embed/sec/suspend/inc",
]
- paths += ["embed/sys/suspend/inc"]
defines += [("USE_SUSPEND", "1")]
if "power_manager" in features_wanted:
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.