1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-22 15:38:11 +00:00

feat(core): introduce powerctl module

[no changelog]
This commit is contained in:
cepetr 2024-11-20 16:24:20 +01:00
parent 8aabdd1f6b
commit 5d64a67479
8 changed files with 380 additions and 2 deletions

View File

@ -295,7 +295,8 @@ env.Replace(
'-ffreestanding ' '-ffreestanding '
'-fstack-protector-all ' '-fstack-protector-all '
+ env.get('ENV')["CPU_CCFLAGS"] + CCFLAGS_MOD, + 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, CPPPATH=ALLPATHS,
CPPDEFINES=[ CPPDEFINES=[
'KERNEL', 'KERNEL',

View File

@ -55,6 +55,10 @@
#include <sec/optiga_transport.h> #include <sec/optiga_transport.h>
#endif #endif
#ifdef USE_POWERCTL
#include <sys/powerctl.h>
#endif
#ifdef USE_PVD #ifdef USE_PVD
#include <sys/pvd.h> #include <sys/pvd.h>
#endif #endif
@ -104,6 +108,10 @@ static void optiga_log_hex(const char *prefix, const uint8_t *data,
#endif #endif
void drivers_init() { void drivers_init() {
#ifdef USE_POWERCTL
powerctl_init();
#endif
#ifdef USE_TAMPER #ifdef USE_TAMPER
tamper_init(); tamper_init();
#endif #endif

View 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_QI,
} 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

View 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

View 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

View 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

View 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

View File

@ -136,8 +136,13 @@ def configure(
sources += [ sources += [
"embed/sys/powerctl/npm1300/npm1300.c", "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 env.get("ENV")["LINKER_SCRIPT"] = linker_script