mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-20 18:16:05 +00:00
feat(core): introduce hibernate mode
[no changelog]
This commit is contained in:
parent
79d14b8907
commit
de73b38aae
@ -547,3 +547,40 @@ Example:
|
||||
optiga-counter-read
|
||||
OK 0E
|
||||
```
|
||||
|
||||
### powerctl-suspend
|
||||
Enters low-power mode.
|
||||
|
||||
In low-power mode, the CPU retains its state, including SRAM content.
|
||||
The device can be woken by pressing the power button and will continue
|
||||
operation from the point where it was suspended.
|
||||
|
||||
Example:
|
||||
```
|
||||
powerctl-suspend
|
||||
# Suspending the device to low-power mode...
|
||||
# Press the POWER button to resume.
|
||||
|
||||
....
|
||||
|
||||
# Resumed to active mode.
|
||||
OK
|
||||
```
|
||||
|
||||
### powerctl-hibernate
|
||||
Enters Hibernate mode.
|
||||
|
||||
In Hibernate mode, the CPU is powered off, and only the VBAT domain remains
|
||||
active. The device can be woken by pressing the power button, triggering
|
||||
a full boot sequence.
|
||||
|
||||
Hibernate mode can only be entered if the device is not connected to a USB or
|
||||
wireless charger.
|
||||
|
||||
Example:
|
||||
```
|
||||
powerctl-hibernate
|
||||
# Hibernating the the device...
|
||||
# Device is powered externally, hibernation is not possible.
|
||||
OK
|
||||
```
|
||||
|
@ -43,6 +43,23 @@ static void prodtest_powerctl_suspend(cli_t* cli) {
|
||||
cli_ok(cli, "");
|
||||
}
|
||||
|
||||
static void prodtest_powerctl_hibernate(cli_t* cli) {
|
||||
if (cli_arg_count(cli) > 0) {
|
||||
cli_error_arg_count(cli);
|
||||
return;
|
||||
}
|
||||
|
||||
cli_trace(cli, "Hibernating the the device...");
|
||||
|
||||
if (!powerctl_hibernate()) {
|
||||
cli_error(cli, CLI_ERROR, "Failed to hibernate.");
|
||||
return;
|
||||
}
|
||||
|
||||
cli_trace(cli, "Device is powered externally, hibernation is not possible.");
|
||||
cli_ok(cli, "");
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
PRODTEST_CLI_CMD(
|
||||
@ -52,4 +69,12 @@ PRODTEST_CLI_CMD(
|
||||
.args = ""
|
||||
);
|
||||
|
||||
PRODTEST_CLI_CMD(
|
||||
.name = "powerctl-hibernate",
|
||||
.func = prodtest_powerctl_hibernate,
|
||||
.info = "Hibernate the device into a near power-off state",
|
||||
.args = ""
|
||||
);
|
||||
|
||||
|
||||
#endif // USE_POWERCTL
|
||||
|
@ -155,6 +155,10 @@ static void show_welcome_screen(void) {
|
||||
}
|
||||
|
||||
static void drivers_init(void) {
|
||||
#ifdef USE_POWERCTL
|
||||
powerctl_init();
|
||||
#endif
|
||||
|
||||
display_init(DISPLAY_RESET_CONTENT);
|
||||
|
||||
#ifdef USE_STORAGE_HWKEY
|
||||
|
@ -49,10 +49,30 @@ typedef struct {
|
||||
} powerctl_status_t;
|
||||
|
||||
// Gets the current power status.
|
||||
void powerctl_get_status(powerctl_status_t* status);
|
||||
//
|
||||
// Returns `true` if the status was successfully retrieved.
|
||||
bool powerctl_get_status(powerctl_status_t* status);
|
||||
|
||||
// Enters low-power mode
|
||||
//
|
||||
// In low-power mode, the CPU retains its state, including SRAM content.
|
||||
// The device can be woken by pressing the power button and will continue
|
||||
// operation from the point where it was suspended.
|
||||
void powerctl_suspend(void);
|
||||
|
||||
// Enters Hibernate mode.
|
||||
//
|
||||
// In Hibernate mode, the CPU is powered off, and only the VBAT domain remains
|
||||
// active. The device can be woken by pressing the power button, triggering
|
||||
// a full boot sequence.
|
||||
//
|
||||
// Hibernate mode can only be entered if the device is not connected to a USB or
|
||||
// wireless charger. If the device is charging, the function returns `true`,
|
||||
// and the device state remains unchanged. If the function succeeds, it does
|
||||
// not return.
|
||||
//
|
||||
// Returns `false` if the operation fails (likely due to uninitialized power
|
||||
// management).
|
||||
bool powerctl_hibernate(void);
|
||||
|
||||
#endif // TREZORHAL_POWERCTL_H
|
||||
|
@ -63,7 +63,21 @@ void npm1300_deinit(void);
|
||||
// Gets the cause of the last restart
|
||||
uint8_t npm1300_restart_cause(void);
|
||||
|
||||
// Switches the device to the ship mode
|
||||
// Switches the device to ship mode.
|
||||
//
|
||||
// In tge ship mode, the CPU is powered off, and only the VBAT domain remains
|
||||
// active. The device can be woken by pressing the power button, triggering
|
||||
// a full boot sequence.
|
||||
//
|
||||
// Ship mode can only be entered if the device is not connected to a USB or
|
||||
// wireless charger. If the device is charging, the function returns `true`,
|
||||
// and the device state remains unchanged.
|
||||
//
|
||||
// If the function succeeds, the device will not be powered off immediately,
|
||||
// but after some time (typically a few milliseconds).
|
||||
//
|
||||
// Returns `false` if the operation fails (likely due to uninitialized power
|
||||
// management).
|
||||
bool npm1300_enter_shipmode(void);
|
||||
|
||||
// Starts the asynchronous measurement
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sys/powerctl.h>
|
||||
#include <sys/systick.h>
|
||||
|
||||
#include "../npm1300/npm1300.h"
|
||||
#include "../stwlc38/stwlc38.h"
|
||||
@ -77,16 +78,35 @@ void powerctl_deinit(void) {
|
||||
drv->initialized = false;
|
||||
}
|
||||
|
||||
void powerctl_get_status(powerctl_status_t* status) {
|
||||
bool 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;
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool powerctl_hibernate(void) {
|
||||
powerctl_driver_t* drv = &g_powerctl_driver;
|
||||
|
||||
if (!drv->initialized) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!npm1300_enter_shipmode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the device to power off
|
||||
systick_delay_ms(50);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // KERNEL_MODE
|
||||
|
@ -726,6 +726,15 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
|
||||
case SYSCALL_POWERCTL_SUSPEND: {
|
||||
powerctl_suspend();
|
||||
} break;
|
||||
|
||||
case SYSCALL_POWERCTL_HIBERNATE: {
|
||||
args[0] = powerctl_hibernate();
|
||||
}
|
||||
|
||||
case SYSCALL_POWERCTL_GET_STATUS: {
|
||||
powerctl_status_t *status = (powerctl_status_t *)args[0];
|
||||
args[0] = powerctl_get_status__verified(status);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_HW_JPEG_DECODER
|
||||
|
@ -147,6 +147,8 @@ typedef enum {
|
||||
SYSCALL_BLE_READ,
|
||||
|
||||
SYSCALL_POWERCTL_SUSPEND,
|
||||
SYSCALL_POWERCTL_HIBERNATE,
|
||||
SYSCALL_POWERCTL_GET_STATUS,
|
||||
|
||||
SYSCALL_JPEGDEC_OPEN,
|
||||
SYSCALL_JPEGDEC_CLOSE,
|
||||
|
@ -685,6 +685,14 @@ uint32_t ble_read(uint8_t *data, uint16_t len) {
|
||||
|
||||
void powerctl_suspend(void) { syscall_invoke0(SYSCALL_POWERCTL_SUSPEND); }
|
||||
|
||||
bool powerctl_hibernate(void) {
|
||||
return (bool)syscall_invoke0(SYSCALL_POWERCTL_HIBERNATE);
|
||||
}
|
||||
|
||||
bool powerctl_get_status(powerctl_status_t *status) {
|
||||
return (bool)syscall_invoke1((uint32_t)status, SYSCALL_POWERCTL_GET_STATUS);
|
||||
}
|
||||
|
||||
#endif // USE_POWERCTL
|
||||
|
||||
// =============================================================================
|
||||
|
@ -783,6 +783,28 @@ access_violation:
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
#ifdef USE_POWERCTL
|
||||
|
||||
bool powerctl_get_status__verified(powerctl_status_t *status) {
|
||||
if (!probe_write_access(status, sizeof(*status))) {
|
||||
goto access_violation;
|
||||
}
|
||||
|
||||
powerctl_status_t status_copy = {0};
|
||||
bool retval = powerctl_get_status(&status_copy);
|
||||
*status = status_copy;
|
||||
|
||||
return retval;
|
||||
|
||||
access_violation:
|
||||
apptask_access_violation();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
#ifdef USE_HW_JPEG_DECODER
|
||||
|
||||
jpegdec_state_t jpegdec_process__verified(jpegdec_input_t *input) {
|
||||
|
@ -202,6 +202,16 @@ secbool ble_read__verified(uint8_t *data, size_t len);
|
||||
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
#ifdef USE_POWERCTL
|
||||
|
||||
#include <sys/powerctl.h>
|
||||
|
||||
bool powerctl_get_status__verified(powerctl_status_t *status);
|
||||
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
#ifdef USE_HW_JPEG_DECODER
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user