From c17ce0e89e26a89be55fb8dfe988b508145f31ff Mon Sep 17 00:00:00 2001 From: cepetr Date: Tue, 17 Jun 2025 14:23:58 +0200 Subject: [PATCH] feat(core): wake up from suspend mode after timeout [no changelog] --- core/SConscript.bootloader | 1 + core/SConscript.kernel | 1 + core/SConscript.prodtest | 1 + core/embed/projects/bootloader/main.c | 10 +- core/embed/projects/kernel/main.c | 8 ++ core/embed/projects/prodtest/main.c | 7 ++ .../sys/power_manager/inc/sys/power_manager.h | 2 +- .../sys/power_manager/stm32u5/power_control.c | 4 +- .../sys/power_manager/stm32u5/power_manager.c | 15 ++- .../stm32u5/power_manager_internal.h | 3 +- core/embed/sys/time/inc/sys/rtc.h | 41 +++++++ core/embed/sys/time/stm32u5/rtc.c | 112 ++++++++++++++++++ .../models/T3W1/trezor_t3w1_revA.py | 4 + .../models/T3W1/trezor_t3w1_revB.py | 4 + .../models/T3W1/trezor_t3w1_revC.py | 4 + core/site_scons/models/stm32u5_common.py | 1 + 16 files changed, 213 insertions(+), 5 deletions(-) create mode 100644 core/embed/sys/time/inc/sys/rtc.h create mode 100644 core/embed/sys/time/stm32u5/rtc.c diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 6c5bee2c63..fec6c75625 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -21,6 +21,7 @@ FEATURES_WANTED = [ "power_manager", "power_save", "rgb_led", + "rtc", "secure_domain", "tropic", "usb", diff --git a/core/SConscript.kernel b/core/SConscript.kernel index 932174fd87..1abbf2576b 100644 --- a/core/SConscript.kernel +++ b/core/SConscript.kernel @@ -42,6 +42,7 @@ FEATURES_WANTED = [ "power_manager", "power_save", "rgb_led", + "rtc", "sd_card", "secmon_layout", "tropic", diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index c8fc239bcb..9b5fb0f023 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -26,6 +26,7 @@ FEATURES_WANTED = [ "power_manager", "power_save", "rgb_led", + "rtc", "sbu", "sd_card", "secure_domain", diff --git a/core/embed/projects/bootloader/main.c b/core/embed/projects/bootloader/main.c index 1c29f06e2b..68b56eb800 100644 --- a/core/embed/projects/bootloader/main.c +++ b/core/embed/projects/bootloader/main.c @@ -59,6 +59,9 @@ #ifdef USE_HASH_PROCESSOR #include #endif +#ifdef USE_RTC +#include +#endif #ifdef USE_TAMPER #include #endif @@ -225,12 +228,17 @@ static void drivers_init(secbool manufacturing_mode, #ifdef USE_HASH_PROCESSOR hash_processor_init(); #endif - display_init(DISPLAY_RESET_CONTENT); #ifdef USE_TAMPER tamper_init(); #endif +#ifdef USE_RTC + rtc_init(); +#endif + + display_init(DISPLAY_RESET_CONTENT); + #ifdef USE_TOUCH *touch_initialized = touch_init(); if (manufacturing_mode != sectrue) { diff --git a/core/embed/projects/kernel/main.c b/core/embed/projects/kernel/main.c index 36da7392ed..fb0dfe728a 100644 --- a/core/embed/projects/kernel/main.c +++ b/core/embed/projects/kernel/main.c @@ -83,6 +83,10 @@ #include #endif +#ifdef USE_RTC +#include +#endif + #ifdef SYSTEM_VIEW #include #endif @@ -122,6 +126,10 @@ void drivers_init() { #endif #endif // SECURE_MODE +#ifdef USE_RTC + rtc_init(); +#endif + #ifdef USE_CONSUMPTION_MASK consumption_mask_init(); #endif diff --git a/core/embed/projects/prodtest/main.c b/core/embed/projects/prodtest/main.c index 456a04898e..cef25d07c1 100644 --- a/core/embed/projects/prodtest/main.c +++ b/core/embed/projects/prodtest/main.c @@ -62,6 +62,10 @@ #include "cmd/prodtest_optiga.h" #endif +#ifdef USE_RTC +#include +#endif + #ifdef USE_TROPIC #include #endif @@ -196,6 +200,9 @@ static bool g_rgbled_control_disabled = false; void prodtest_disable_rgbled_control(void) { g_rgbled_control_disabled = true; } static void drivers_init(void) { +#ifdef USE_RTC + rtc_init(); +#endif #ifdef USE_BACKUP_RAM backup_ram_init(); #endif diff --git a/core/embed/sys/power_manager/inc/sys/power_manager.h b/core/embed/sys/power_manager/inc/sys/power_manager.h index 6b63e2c0f7..e239bb9461 100644 --- a/core/embed/sys/power_manager/inc/sys/power_manager.h +++ b/core/embed/sys/power_manager/inc/sys/power_manager.h @@ -28,7 +28,7 @@ typedef enum { PM_WAKEUP_FLAG_BLE = 0x1 << 2, // Bluetooth connection event PM_WAKEUP_FLAG_NFC = 0x1 << 3, // NFC event PM_WAKEUP_FLAG_USB = 0x1 << 4, // USB event - PM_WAKEUP_FLAG_TIMER = 0x1 << 5, // Timer event + PM_WAKEUP_FLAG_RTC = 0x1 << 5, // RTC wake-up timer } pm_wakeup_flags_t; /* power manager status codes */ diff --git a/core/embed/sys/power_manager/stm32u5/power_control.c b/core/embed/sys/power_manager/stm32u5/power_control.c index aa5b4865c7..8f752d534c 100644 --- a/core/embed/sys/power_manager/stm32u5/power_control.c +++ b/core/embed/sys/power_manager/stm32u5/power_control.c @@ -41,7 +41,7 @@ pm_status_t pm_control_hibernate() { return PM_ERROR; } -void pm_control_suspend() { +pm_wakeup_flags_t pm_control_suspend(void) { // Clear all wakeup flags. From this point, any wakeup event that // sets a wakeup flag causes this function to return. pm_wakeup_flags_reset(); @@ -94,6 +94,8 @@ void pm_control_suspend() { // Reinitialize all drivers that were stopped earlier power_save_resume_io(&wakeup_params); + + return wakeup_flags; } static void pm_background_tasks_suspend(void) {} diff --git a/core/embed/sys/power_manager/stm32u5/power_manager.c b/core/embed/sys/power_manager/stm32u5/power_manager.c index e8241307e1..a8b1fe156d 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager.c +++ b/core/embed/sys/power_manager/stm32u5/power_manager.c @@ -25,6 +25,10 @@ #include #include +#ifdef USE_RTC +#include +#endif + #include "../power_manager_poll.h" #include "../stwlc38/stwlc38.h" #include "power_manager_internal.h" @@ -223,7 +227,16 @@ pm_status_t pm_suspend(void) { irq_unlock(irq_key); - pm_control_suspend(); +#ifdef USE_RTC + // TODO: Uncomment to wake up by RTC timer + // Automatically wakes up after 10 seconds with PM_WAKEUP_FLAG_RTC set + // rtc_wakeup_timer_start(10); +#endif + + pm_wakeup_flags_t wakeup_flags = pm_control_suspend(); + + // TODO: Handle wake-up flags + UNUSED(wakeup_flags); // Exit hibernation state if it was requested irq_key = irq_lock(); 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 cfc178d28b..cc26f529e9 100644 --- a/core/embed/sys/power_manager/stm32u5/power_manager_internal.h +++ b/core/embed/sys/power_manager/stm32u5/power_manager_internal.h @@ -141,4 +141,5 @@ void pm_battery_initial_soc_guess(void); pm_status_t pm_control_hibernate(void); // Power manager control function which puts device into suspend mode. -void pm_control_suspend(void); +// Returns the wakeup flags that caused the device to wake up. +pm_wakeup_flags_t pm_control_suspend(void); diff --git a/core/embed/sys/time/inc/sys/rtc.h b/core/embed/sys/time/inc/sys/rtc.h new file mode 100644 index 0000000000..799de0ad82 --- /dev/null +++ b/core/embed/sys/time/inc/sys/rtc.h @@ -0,0 +1,41 @@ +/* + * 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 . + */ + +#pragma once + +/** + * @brief Initialize the RTC driver + * + * Before initialization, the RCC clock for the RTC must be configured to + * 32.768 kHz (using either LSE or LSI). + * + * @return true if initialization was successful, false otherwise + */ +bool rtc_init(void); + +/** + * @brief Schedule a wakeup event after a specified number of seconds + * + * Configures the RTC to wake up the system from STOP mode after the specified + * number of seconds. After waking up, the PM_WAKEUP_FLAG_RTC flag is set. + * + * @param seconds Number of seconds (1 to 65536) to wait before waking up. + * @return true if the wakeup was successfully scheduled, false otherwise + */ +bool rtc_wakeup_timer_start(uint32_t seconds); diff --git a/core/embed/sys/time/stm32u5/rtc.c b/core/embed/sys/time/stm32u5/rtc.c new file mode 100644 index 0000000000..8133df17d0 --- /dev/null +++ b/core/embed/sys/time/stm32u5/rtc.c @@ -0,0 +1,112 @@ +/* + * 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 . + */ + +#ifdef KERNEL_MODE + +#include +#include + +#include +#include +#include +#include + +// RTC driver structure +typedef struct { + bool initialized; + RTC_HandleTypeDef hrtc; +} rtc_driver_t; + +// RTC driver instance +static rtc_driver_t g_rtc_driver = { + .initialized = false, +}; + +bool rtc_init(void) { + rtc_driver_t* drv = &g_rtc_driver; + + if (drv->initialized) { + return true; + } + + memset(drv, 0, sizeof(rtc_driver_t)); + + drv->hrtc.Instance = RTC; + drv->hrtc.Init.HourFormat = RTC_HOURFORMAT_24; + drv->hrtc.Init.AsynchPrediv = 128 - 1; + drv->hrtc.Init.SynchPrediv = 256 - 1; + drv->hrtc.Init.OutPut = RTC_OUTPUT_DISABLE; + drv->hrtc.Init.BinMode = RTC_BINARY_NONE; + + if (HAL_OK != HAL_RTC_Init(&drv->hrtc)) { + return false; + } + + // Allow waking up from STOP mode + RCC->APB3SMENR &= ~RCC_APB3SMENR_RTCAPBSMEN; + RCC->SRDAMR |= RCC_SRDAMR_RTCAPBAMEN; + + NVIC_ClearPendingIRQ(RTC_IRQn); + NVIC_SetPriority(RTC_IRQn, IRQ_PRI_NORMAL); + NVIC_EnableIRQ(RTC_IRQn); + + drv->initialized = true; + return true; +} + +bool rtc_wakeup_timer_start(uint32_t seconds) { + rtc_driver_t* drv = &g_rtc_driver; + + if (!drv->initialized) { + return false; + } + + if (seconds < 1 || seconds > 0x10000) { + return false; + } + + HAL_StatusTypeDef status; + + status = HAL_RTCEx_SetWakeUpTimer_IT(&drv->hrtc, seconds - 1, + RTC_WAKEUPCLOCK_CK_SPRE_16BITS, 0); + if (HAL_OK != status) { + return false; + } + + return true; +} + +void RTC_IRQHandler(void) { + IRQ_LOG_ENTER(); + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_DEFAULT); + + if (READ_BIT(RTC->MISR, RTC_MISR_WUTMF) != 0U) { + // Clear the wakeup timer interrupt flag + WRITE_REG(RTC->SCR, RTC_SCR_CWUTF); + // Deactivate the wakeup timer to prevent re-triggering + HAL_RTCEx_DeactivateWakeUpTimer(&g_rtc_driver.hrtc); + // Signal the wakeup event to the power manager + pm_wakeup_flags_set(PM_WAKEUP_FLAG_RTC); + } + + mpu_restore(mpu_mode); + IRQ_LOG_EXIT(); +} + +#endif // KERNEL_MODE diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revA.py b/core/site_scons/models/T3W1/trezor_t3w1_revA.py index b1cae1b6bb..b22c1ecfd5 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revA.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revA.py @@ -97,6 +97,10 @@ def configure( paths += ["embed/sys/backup_ram/inc"] defines += [("USE_BACKUP_RAM", "1")] + if "rtc" in features_wanted: + sources += ["embed/sys/time/stm32u5/rtc.c"] + defines += [("USE_RTC", "1")] + if "haptic" in features_wanted: sources += [ "embed/io/haptic/drv2625/drv2625.c", diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revB.py b/core/site_scons/models/T3W1/trezor_t3w1_revB.py index 58d919c974..00daaa3fc3 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revB.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revB.py @@ -98,6 +98,10 @@ def configure( paths += ["embed/sys/backup_ram/inc"] defines += [("USE_BACKUP_RAM", "1")] + if "rtc" in features_wanted: + sources += ["embed/sys/time/stm32u5/rtc.c"] + defines += [("USE_RTC", "1")] + if "haptic" in features_wanted: sources += [ "embed/io/haptic/drv2625/drv2625.c", diff --git a/core/site_scons/models/T3W1/trezor_t3w1_revC.py b/core/site_scons/models/T3W1/trezor_t3w1_revC.py index 48a6cfa20d..bb42dd4c12 100644 --- a/core/site_scons/models/T3W1/trezor_t3w1_revC.py +++ b/core/site_scons/models/T3W1/trezor_t3w1_revC.py @@ -97,6 +97,10 @@ def configure( paths += ["embed/sys/backup_ram/inc"] defines += [("USE_BACKUP_RAM", "1")] + if "rtc" in features_wanted: + sources += ["embed/sys/time/stm32u5/rtc.c"] + defines += [("USE_RTC", "1")] + if "haptic" in features_wanted: sources += [ "embed/io/haptic/drv2625/drv2625.c", diff --git a/core/site_scons/models/stm32u5_common.py b/core/site_scons/models/stm32u5_common.py index a781f57470..2f768f1e76 100644 --- a/core/site_scons/models/stm32u5_common.py +++ b/core/site_scons/models/stm32u5_common.py @@ -73,6 +73,7 @@ def stm32u5_common_files(env, features_wanted, defines, sources, paths): "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_rcc.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_rcc_ex.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_rtc.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_rtc_ex.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_spi.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_sram.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_tim.c",