mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-11 17:08:15 +00:00
feat(core): introduce powerctl module
[no changelog]
This commit is contained in:
parent
3b4e451dad
commit
d5c42dfceb
@ -309,7 +309,8 @@ env.Replace(
|
||||
'-ffreestanding '
|
||||
'-fstack-protector-all '
|
||||
+ env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD,
|
||||
LINKFLAGS='-T build/kernel/memory.ld -Wl,--gc-sections -Wl,--print-memory-usage -Wl,-Map=build/kernel/kernel.map -Wl,--warn-common',
|
||||
LINKFLAGS='-T build/kernel/memory.ld -Wl,--gc-sections -Wl,--print-memory-usage '
|
||||
' -Wl,-Map=build/kernel/kernel.map -Wl,--warn-common -Wl,--undefined=__errno',
|
||||
CPPPATH=ALLPATHS,
|
||||
CPPDEFINES=[
|
||||
'KERNEL',
|
||||
|
@ -55,6 +55,10 @@
|
||||
#include <sec/optiga_transport.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_POWERCTL
|
||||
#include <sys/powerctl.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_PVD
|
||||
#include <sys/pvd.h>
|
||||
#endif
|
||||
@ -104,6 +108,10 @@ static void optiga_log_hex(const char *prefix, const uint8_t *data,
|
||||
#endif
|
||||
|
||||
void drivers_init() {
|
||||
#ifdef USE_POWERCTL
|
||||
powerctl_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_TAMPER
|
||||
tamper_init();
|
||||
#endif
|
||||
|
58
core/embed/sys/powerctl/inc/sys/powerctl.h
Normal file
58
core/embed/sys/powerctl/inc/sys/powerctl.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 TREZORHAL_POWERCTL_H
|
||||
#define TREZORHAL_POWERCTL_H
|
||||
|
||||
// Initializes power control module.
|
||||
//
|
||||
// Returns true if the initialization was successful.
|
||||
bool powerctl_init(void);
|
||||
|
||||
// Deinitializes power control module.
|
||||
void powerctl_deinit(void);
|
||||
|
||||
typedef enum {
|
||||
POWER_SOURCE_BATT,
|
||||
POWER_SOURCE_USB,
|
||||
POWER_SOURCE_WIRELESS,
|
||||
} power_source_t;
|
||||
|
||||
typedef struct {
|
||||
// Current power source
|
||||
power_source_t power_source;
|
||||
// Set if charging is active
|
||||
bool charging;
|
||||
// Battery charge level in percents
|
||||
// (or -1 if the battery level is unknown)
|
||||
int charge_level;
|
||||
// Set if the temperature is too low
|
||||
bool low_temperature;
|
||||
// Set if the temperature is too high
|
||||
bool high_temperature;
|
||||
} powerctl_status_t;
|
||||
|
||||
// Gets the current power status.
|
||||
void powerctl_get_status(powerctl_status_t* status);
|
||||
|
||||
// Enters low-power mode
|
||||
//
|
||||
void powerctl_suspend(void);
|
||||
|
||||
#endif // TREZORHAL_POWERCTL_H
|
44
core/embed/sys/powerctl/inc/sys/wakeup_flags.h
Normal file
44
core/embed/sys/powerctl/inc/sys/wakeup_flags.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 TREZORHAL_WAKEUP_FLAGS_H
|
||||
#define TREZORHAL_WAKEUP_FLAGS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Wakeup flags used to signal the reason of the wakeup
|
||||
// from the STOP mode
|
||||
|
||||
#define WAKEUP_FLAG_BUTTON 0x01 // Button pressed
|
||||
#define WAKEUP_FLAG_WPC 0x02 // Wireless power charging event
|
||||
#define WAKEUP_FLAG_BLE 0x04 // Bluetooth connection event
|
||||
#define WAKEUP_FLAG_NFC 0x08 // NFC event
|
||||
#define WAKEUP_FLAG_USB 0x10 // USB event
|
||||
#define WAKEUP_FLAG_TIMER 0x20 // Timer event
|
||||
|
||||
// Sets the wakeup flag
|
||||
void wakeup_flags_set(uint16_t flags);
|
||||
|
||||
// Resets all wakeup flags
|
||||
void wakeup_flags_reset(void);
|
||||
|
||||
// Gets current wakeup flags
|
||||
uint16_t wakeup_flags_get(void);
|
||||
|
||||
#endif // TREZORHAL_WAKEUP_FLAGS_H
|
92
core/embed/sys/powerctl/stm32u5/powerctl.c
Normal file
92
core/embed/sys/powerctl/stm32u5/powerctl.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <trezor_bsp.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sys/powerctl.h>
|
||||
|
||||
#include "../npm1300/npm1300.h"
|
||||
#include "../stwlc38/stwlc38.h"
|
||||
|
||||
#ifdef KERNEL_MODE
|
||||
|
||||
// Power control driver state
|
||||
typedef struct {
|
||||
// True if the driver is initialized
|
||||
bool initialized;
|
||||
|
||||
} powerctl_driver_t;
|
||||
|
||||
// Power control driver instance
|
||||
static powerctl_driver_t g_powerctl_driver = {.initialized = false};
|
||||
|
||||
bool powerctl_init(void) {
|
||||
powerctl_driver_t* drv = &g_powerctl_driver;
|
||||
|
||||
if (drv->initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialize PMIC
|
||||
if (!npm1300_init()) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Initialize wireless charging
|
||||
if (!stwlc38_init()) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
drv->initialized = true;
|
||||
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
stwlc38_deinit();
|
||||
npm1300_deinit();
|
||||
return false;
|
||||
}
|
||||
|
||||
void powerctl_deinit(void) {
|
||||
powerctl_driver_t* drv = &g_powerctl_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
stwlc38_deinit();
|
||||
npm1300_deinit();
|
||||
|
||||
drv->initialized = false;
|
||||
}
|
||||
|
||||
void powerctl_get_status(powerctl_status_t* status) {
|
||||
powerctl_driver_t* drv = &g_powerctl_driver;
|
||||
|
||||
memset(status, 0, sizeof(powerctl_status_t));
|
||||
|
||||
if (!drv->initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
#endif // KERNEL_MODE
|
124
core/embed/sys/powerctl/stm32u5/powerctl_suspend.c
Normal file
124
core/embed/sys/powerctl/stm32u5/powerctl_suspend.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <trezor_bsp.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <io/display.h>
|
||||
#include <io/usb.h>
|
||||
#include <sys/irq.h>
|
||||
#include <sys/wakeup_flags.h>
|
||||
|
||||
#ifdef USE_TOUCH
|
||||
#include <io/touch.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_HAPTIC
|
||||
#include <io/haptic.h>
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL_MODE
|
||||
|
||||
static void background_tasks_suspend(void) {
|
||||
// stwlc38
|
||||
// npm1300
|
||||
// nrf52
|
||||
// ble
|
||||
// powerctl
|
||||
}
|
||||
|
||||
static bool background_tasks_suspended(void) { return true; }
|
||||
|
||||
static void background_tasks_resume(void) {}
|
||||
|
||||
void powerctl_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();
|
||||
|
||||
// Deinitialize all drivers that are not required in low-power mode
|
||||
// (e.g., USB, display, touch, haptic, etc.).
|
||||
usb_stop();
|
||||
#ifdef USE_HAPTIC
|
||||
haptic_deinit();
|
||||
#endif
|
||||
#ifdef USE_TOUCH
|
||||
touch_deinit();
|
||||
#endif
|
||||
int backlight_level = display_get_backlight();
|
||||
display_deinit(DISPLAY_RESET_CONTENT);
|
||||
|
||||
// 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_get() == 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.
|
||||
|
||||
} while (!background_tasks_suspended() && (wakeup_flags_get() == 0));
|
||||
|
||||
if (wakeup_flags_get() == 0) {
|
||||
// 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();
|
||||
|
||||
// Enter STOP2 mode
|
||||
HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
|
||||
|
||||
// Recover system clock
|
||||
SystemInit();
|
||||
|
||||
irq_unlock(irq_key);
|
||||
|
||||
// At this point, all pending interrupts are processed.
|
||||
// Some of them may set wakeup flags.
|
||||
}
|
||||
|
||||
// Resume state machines running in the interrupt context
|
||||
background_tasks_resume();
|
||||
}
|
||||
|
||||
// Reinitialize all drivers that were stopped earlier
|
||||
display_init(DISPLAY_RESET_CONTENT);
|
||||
display_set_backlight(backlight_level);
|
||||
#ifdef USE_TOUCH
|
||||
touch_init();
|
||||
#endif
|
||||
#ifdef USE_HAPTIC
|
||||
haptic_init();
|
||||
#endif
|
||||
usb_start();
|
||||
}
|
||||
|
||||
#endif // KERNEL_MODE
|
46
core/embed/sys/powerctl/wakeup_flags.c
Normal file
46
core/embed/sys/powerctl/wakeup_flags.c
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <sys/irq.h>
|
||||
#include <sys/wakeup_flags.h>
|
||||
|
||||
#ifdef KERNEL_MODE
|
||||
|
||||
static uint16_t g_wakeup_flags = 0;
|
||||
|
||||
void wakeup_flags_set(uint16_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);
|
||||
}
|
||||
|
||||
uint16_t wakeup_flags_get(void) {
|
||||
irq_key_t irq_key = irq_lock();
|
||||
uint16_t flags = g_wakeup_flags;
|
||||
irq_unlock(irq_key);
|
||||
return flags;
|
||||
}
|
||||
|
||||
#endif // KERNEL_MODE
|
@ -149,8 +149,13 @@ def configure(
|
||||
|
||||
sources += [
|
||||
"embed/sys/powerctl/npm1300/npm1300.c",
|
||||
"embed/sys/powerctl/stwlc38/stwlc38.c"
|
||||
"embed/sys/powerctl/stwlc38/stwlc38.c",
|
||||
"embed/sys/powerctl/stm32u5/powerctl.c",
|
||||
"embed/sys/powerctl/stm32u5/powerctl_suspend.c",
|
||||
"embed/sys/powerctl/wakeup_flags.c",
|
||||
]
|
||||
paths += ["embed/sys/powerctl/inc"]
|
||||
defines += [("USE_POWERCTL", "1")]
|
||||
|
||||
env.get("ENV")["LINKER_SCRIPT"] = linker_script
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user