mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-03-27 13:35:44 +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
|
optiga-counter-read
|
||||||
OK 0E
|
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, "");
|
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
|
// clang-format off
|
||||||
|
|
||||||
PRODTEST_CLI_CMD(
|
PRODTEST_CLI_CMD(
|
||||||
@ -52,4 +69,12 @@ PRODTEST_CLI_CMD(
|
|||||||
.args = ""
|
.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
|
#endif // USE_POWERCTL
|
||||||
|
@ -155,6 +155,10 @@ static void show_welcome_screen(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void drivers_init(void) {
|
static void drivers_init(void) {
|
||||||
|
#ifdef USE_POWERCTL
|
||||||
|
powerctl_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
display_init(DISPLAY_RESET_CONTENT);
|
display_init(DISPLAY_RESET_CONTENT);
|
||||||
|
|
||||||
#ifdef USE_STORAGE_HWKEY
|
#ifdef USE_STORAGE_HWKEY
|
||||||
|
@ -49,10 +49,30 @@ typedef struct {
|
|||||||
} powerctl_status_t;
|
} powerctl_status_t;
|
||||||
|
|
||||||
// Gets the current power status.
|
// 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
|
// 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);
|
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
|
#endif // TREZORHAL_POWERCTL_H
|
||||||
|
@ -63,7 +63,21 @@ void npm1300_deinit(void);
|
|||||||
// Gets the cause of the last restart
|
// Gets the cause of the last restart
|
||||||
uint8_t npm1300_restart_cause(void);
|
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);
|
bool npm1300_enter_shipmode(void);
|
||||||
|
|
||||||
// Starts the asynchronous measurement
|
// Starts the asynchronous measurement
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <trezor_rtl.h>
|
#include <trezor_rtl.h>
|
||||||
|
|
||||||
#include <sys/powerctl.h>
|
#include <sys/powerctl.h>
|
||||||
|
#include <sys/systick.h>
|
||||||
|
|
||||||
#include "../npm1300/npm1300.h"
|
#include "../npm1300/npm1300.h"
|
||||||
#include "../stwlc38/stwlc38.h"
|
#include "../stwlc38/stwlc38.h"
|
||||||
@ -77,16 +78,35 @@ void powerctl_deinit(void) {
|
|||||||
drv->initialized = false;
|
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;
|
powerctl_driver_t* drv = &g_powerctl_driver;
|
||||||
|
|
||||||
memset(status, 0, sizeof(powerctl_status_t));
|
memset(status, 0, sizeof(powerctl_status_t));
|
||||||
|
|
||||||
if (!drv->initialized) {
|
if (!drv->initialized) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// 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
|
#endif // KERNEL_MODE
|
||||||
|
@ -726,6 +726,15 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args,
|
|||||||
case SYSCALL_POWERCTL_SUSPEND: {
|
case SYSCALL_POWERCTL_SUSPEND: {
|
||||||
powerctl_suspend();
|
powerctl_suspend();
|
||||||
} break;
|
} 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
|
#endif
|
||||||
|
|
||||||
#ifdef USE_HW_JPEG_DECODER
|
#ifdef USE_HW_JPEG_DECODER
|
||||||
|
@ -147,6 +147,8 @@ typedef enum {
|
|||||||
SYSCALL_BLE_READ,
|
SYSCALL_BLE_READ,
|
||||||
|
|
||||||
SYSCALL_POWERCTL_SUSPEND,
|
SYSCALL_POWERCTL_SUSPEND,
|
||||||
|
SYSCALL_POWERCTL_HIBERNATE,
|
||||||
|
SYSCALL_POWERCTL_GET_STATUS,
|
||||||
|
|
||||||
SYSCALL_JPEGDEC_OPEN,
|
SYSCALL_JPEGDEC_OPEN,
|
||||||
SYSCALL_JPEGDEC_CLOSE,
|
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); }
|
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
|
#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
|
#ifdef USE_HW_JPEG_DECODER
|
||||||
|
|
||||||
jpegdec_state_t jpegdec_process__verified(jpegdec_input_t *input) {
|
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
|
#endif
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifdef USE_POWERCTL
|
||||||
|
|
||||||
|
#include <sys/powerctl.h>
|
||||||
|
|
||||||
|
bool powerctl_get_status__verified(powerctl_status_t *status);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
#ifdef USE_HW_JPEG_DECODER
|
#ifdef USE_HW_JPEG_DECODER
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user