Suspend/Resume (Linux)
Introduction
The Linux kernel can support up to four system sleep states depending on the capabilities of the platform it runs on. In this article, we will explore platform-specific implementations for Toradex SoMs.
Torizon OS
The information provided throughout this article is also applicable to Torizon OS.
In addition, you may want to control the power state in your containerized application. Learn how to use containers to reboot, suspend and resume in the Torizon Best Practices article.
Suspend/Resume on Toradex SoMs
When the CPU is not running, the processor can enter the low power mode. The chip supports a very flexible set of power mode configurations in low power mode:
System Idle: The CPU can enter this mode automatically if there is no thread running anymore. All peripherals can be kept working. The CPU state is retained, so the interrupt response can be very short.
Low Power Idle: Some of the peripherals are kept still alive while others are shut off. The interrupt response in this state is longer than in the System Idle, but the power consumption is much lower.
Suspend: All clocks, unused peripherals, and PHYs are off. The DDR3L RAM stays in SelfRefresh mode. The exit time from this mode is much longer. All power rails are still available on the module.
NXP i.MX 6/6 ULL/7-based Modules
The low power mode can be activated through the following command:
# echo standby > /sys/power/state
The suspend mode can be activated through the following command:
# echo mem > /sys/power/state
In order to wake the system up again, the MXM3 PIN 37 (Apalis iMX6) or SODIMM PIN 45 (Colibri iMX6/6ULL/7) need to be pulled up or down, depending on the previous state. RTC wake-up can also be used.
NXP i.MX 8/8X and i.MX 8M Mini/Plus-based Modules
The Wi-Fi subsystem currently does not support suspend. Thus the related kernel module needs to be unloaded.
# modprobe -r mwifiex_sdio
Two sleep states are supported by the Linux kernel on the Colibri iMX8X, Apalis iMX8 and Verdin iMX8M Mini and Plus modules: Suspend-to-RAM and Suspend-to-Idle.
Suspend-to-RAM (deep) State: To enter Suspend-to-RAM state
# echo deep > /sys/power/mem_sleep; echo mem > /sys/power/state
The system will wake up with
WAKE1_MICO#
(SODIMM_252, X7-24) pin or with a console keypress. You can also set the system to wake up with RTC alarm in 5 secs from now, for example:# echo +5 > /sys/class/rtc/rtc1/wakealarm; echo deep > /sys/power/mem_sleep; echo mem > /sys/power/state
Suspend-to-Idle (S2Idle): To enter S2Idle state
# echo s2idle > /sys/power/mem_sleep; echo mem > /sys/power/state
NXP Vybrid-based Modules
Disable Ethernet PHY: To suspend/resume your Colibri VF50/VF61, you must disable the ethernet PHY. The Ethernet PHY used on our Vybrid-based modules has an errata which does not allow the PHY to power down and wake-up reliable. Therefore, suspend mode for the Ethernet PHY has been disabled by default (by this commit).
For low-power applications not using Ethernet, it is recommended to set the PHY to power-down mode in U-Boot and disable the PHY driver in Linux. To disable PHY control from Linux either disable the Ethernet and PHY driver in the kernel configuration or remove the corresponding device tree node (e.g. set the
status
property of the fec node todisabled
see Device Tree Customization).Use the following U-Boot command to disable the Ethernet PHY:
> mii write 0 0 0x3800
Extend the bootcmd to disable the Ethernet PHY by default:
> setenv bootcmd "mii write 0 0 0x3800 && ${bootcmd}"
> saveenvStandby mode: The standby sleep state puts the Vybrid SoC in STOP mode. The SoC can be woken from standby through any peripheral interrupt. However, currently, wake-up capabilities have been implemented and tested only for some peripheral drivers, namely GPIO, SNVS RTC and UART driver.
Entering standby mode:
# echo standby > /sys/power/state
Suspend-to-RAM mode: The mem sleep state (Suspend-to-RAM) uses Vybrid's LPSTOP2 mode. This mode powergates most parts of the SoC expect some peripherals such as Wake-Up controller (WKPU) or LP RTC. The main memory (DDR3) is put into self-refresh mode. The SoC can be woken from mem sleep state through wake-up GPIOs or internal SNVS RTC.
Entering in suspend to mem mode:
# echo mem > /sys/power/state
Or
# systemctl suspend
info- Suspend to mem mode is supported since V1.2A module revision.
- There are few systemd services which are used as a workaround for a known issue with USB host not working after using LPSTOP suspend mode. To make sure USB is working on resume from a suspend to mem, use
systemctl suspend
to initiate suspend to mem.
NVIDIA Tegra-based Modules
The Apalis T30/TK1 and Colibri T20/T30, based on NVIDIA Tegra T20, T30 and TK1 processors, support Low Power modes (LP). Currently, LP1 is supported which means CPU is put into a sleep mode and RAM is in self-refresh mode:
# echo mem > /sys/power/state
In order to wake the system up again, the MXM3 PIN 37 need to be pulled up or down (depending on the previous state).
The suspend mode can be selected using /sys/power/suspend/mode
. But currently, only LP1 is supported.
General Wake-up Methods
GPIO
Toradex device trees set up GPIO pins as the default wakeup source. They are defined under the gpio-keys
node, muxed to use the ALT5 function.
- Colibri: SODIMM PIN 43 and/or SODIMM PIN 45
- Apalis: MXM3 PIN 37 (
WAKE1_MICO
) - Verdin: SODIMM 252 (
CTRL_WAKE1_MICO
)
RTC
The below example sets the timeout (in seconds) to wakeup from standby/suspend.
# echo +10 > /sys/class/rtc/rtc1/wakealarm
If the system is woken up before the configured timeout (for example, using a GPIO), and you attempt to set the timeout again before the original one expires, you will encounter the error device or resource busy
. Example:
# echo +1000 > /sys/class/rtc/rtc1/wakealarm && echo mem > /sys/power/state
At this point, the system is waken up before the RTC's timeout went out (e.g. via a wakeup source GPIO), and it is not possible to reconfigure the wakealarm
.
# echo +10 > /sys/class/rtc/rtc1/wakealarm
echo: write error: Device or resource busy
To circumvent this behavior, you should first reset the wakealarm
:
# echo +0 > /sys/class/rtc/rtc1/wakealarm
Then, it will be possible to configure the wakealarm
again for another cycle.
UART
The UART can be used as a wake-up source, but only for standby mode
# echo enabled > /sys/class/tty/ttyLP0/power/wakeup
# echo enabled > /sys/class/tty/ttymxc0/power/wakeup
The below example enables ttymxc0 as wake-up source on the iMX8M Mini.
# echo enabled > /sys/class/tty/ttymxc0/power/wakeup
The below example enables ttymxc2 as wake-up source on the iMX8M Plus.
# echo enabled > /sys/class/tty/ttymxc2/power/wakeup
The below example enables ttyLP0 as wake-up source on the Apalis iMX8, but you can also enable ttyLP1
, ttyLP2
or ttyLP3
to perform the same task. The UART wakeup on Colibri iMX8X works the same way.
# echo enabled > /sys/class/tty/ttyLP0/power/wakeup
Signaling Suspend/Resume Events to an Application
If there is the need to make an application aware of the Suspend/Resume events, one can use Systemd to accomplish it.
Creating Customized Suspend/Resume Related Services
Systemd has in place the systemd-suspend.service
(Reference: https://www.freedesktop.org/software/systemd/man/systemd-sleep.conf.html#SuspendMode=), which can be used by the developer to create other services the are nedded to be executed before entering suspend mode (before the systend-suspend.service
) and/or after resuming ( after the systend-suspend.service
).
Taking action before suspend: The sample service below will send the signal USR1 (
SIGUSR1
) to an application right before the system entering in suspend mode. It can be saved as/etc/systemd/system/signal_before_suspend.service
.[Unit]
Description=Sends signal USR1 to application signal_test before system entering in suspend mode.
Before=sleep.target
[Service]
Type=oneshot
ExecStart=killall -s SIGUSR1 signal_test
User=root
[Install]
RequiredBy=sleep.targetActivating the service:
$ systemctl enable signal_before_suspend.service
Starting the service:
$ systemctl start signal_before_suspend.service
Taking action after resume: The sample service below will send the signal USR2 (
SIGUSR2
) to an application right after the system resuming. It can be saved as/etc/systemd/system/signal_after_resume.service
.```
[Unit]
Description=Sends signal USR2 to application signal_test before system resumes.
After=sleep.target
[Service]
Type=oneshot
ExecStart=killall -s SIGUSR2 signal_test
User=root
[Install]
RequiredBy=sleep.target
```
Activating the service:
```
$ systemctl enable signal_after_resume.service
```
Starting the service:
```
$ systemctl start signal_after_resume.service
```