3.3.6. Wakeup Sources
This section talks about the multiple ways in which we can wakeup the AM62x SoC from Low Power modes like Deep Sleep or MCU only. The AM62x SoC support various wakeup sources like GP Timers, RTC Timer, UART, I2C, WKUP GPIO, and I/O Daisy Chain.
The table below lists the wakeup sources supported in this SDK release and whether that source is valid for given low power modes:
Wakeup Source |
Deep Sleep |
MCU Only |
Partial I/O |
---|---|---|---|
Real-Time Clock (RTC) |
Yes |
Yes |
No |
MCU (WKUP) GPIO |
Yes |
Yes |
No |
Main I/O Daisy Chain (Main GPIO and Main UART) |
Yes |
Yes |
No |
USB Wakeup |
Yes |
Yes |
No |
WKUP UART |
Yes |
Yes |
No |
MCU IPC (for MCU Only mode) |
No |
Yes |
No |
CAN UART I/O Daisy Chain |
No |
No |
Yes |
3.3.6.1. Real-Time Clock (RTC)
It’s possible to use the SoC’s internal RTC to wakeup the system using the command rtcwake:
rtcwake
- Show whether an alarm is set or not:
rtcwake -m show -v
- Suspend to RAM and wakeup after 10 seconds:
rtcwake -m mem -s {{10}}
- Disable a previously set alarm:
rtcwake -m disable
- Perform a dry run to wakeup the computer at a given time. (Press Ctrl + C to abort):
rtcwake -m on --date {{hh:ss}}
For example, if you wish to wakeup from Deep Sleep or MCU Only mode in 10 seconds, use the command like this:
Note
An additional -d rtc1
option is required on BeaglePlay as the SoC’s
internal RTC gets probed as rtc1
root@am62xx-evm:~# rtcwake -s 10 -m mem
rtcwake: wakeup from "mem" using /dev/rtc0 at Thu Jan 1 00:00:45 1970
[ 28.038332] PM: suspend entry (deep)
[ 28.042057] Filesystems sync: 0.000 seconds
[ 28.050312] Freezing user space processes
[ 28.052137] Freezing user space processes completed (elapsed 0.001 seconds)
[ 28.052162] OOM killer disabled.
[ 28.052166] Freezing remaining freezable tasks
[ 28.053557] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
[ 28.053571] printk: Suspending console(s) (use no_console_suspend to debug)
[ 28.138190] ti-sci 44043000.system-controller: ti_sci_cmd_set_device_constraint: device: 179: state: 1: ret 0
[ 28.148680] ti-sci 44043000.system-controller: ti_sci_cmd_set_device_constraint: device: 178: state: 1: ret 0
[ 29.911265] omap8250 2800000.serial: PM domain pd:146 will not be powered off
[ 29.923288] ti-sci 44043000.system-controller: ti_sci_cmd_set_device_constraint: device: 117: state: 1: ret 0
[ 30.789584] remoteproc remoteproc0: stopped remote processor 5000000.m4fss
[ 30.981215] Disabling non-boot CPUs ...
[ 30.983394] psci: CPU1 killed (polled 0 ms)
[ 30.986714] psci: CPU2 killed (polled 0 ms)
[ 30.990028] psci: CPU3 killed (polled 0 ms)
[ 30.991437] Enabling non-boot CPUs ...
[ 31.011850] Detected VIPT I-cache on CPU1
[ 31.011909] GICv3: CPU1: found redistributor 1 region 0:0x00000000018a0000
[ 31.011972] CPU1: Booted secondary processor 0x0000000001 [0x410fd034]
[ 31.013028] CPU1 is up
[ 31.033291] Detected VIPT I-cache on CPU2
[ 31.033322] GICv3: CPU2: found redistributor 2 region 0:0x00000000018c0000
[ 31.033365] CPU2: Booted secondary processor 0x0000000002 [0x410fd034]
[ 31.034221] CPU2 is up
[ 31.054487] Detected VIPT I-cache on CPU3
[ 31.054524] GICv3: CPU3: found redistributor 3 region 0:0x00000000018e0000
[ 31.054573] CPU3: Booted secondary processor 0x0000000003 [0x410fd034]
[ 31.055431] CPU3 is up
[ 31.058242] ti-sci 44043000.system-controller: ti_sci_resume: wakeup source: 0x50
[ 33.771971] am65-cpsw-nuss 8000000.ethernet: set new flow-id-base 19
[ 34.177716] am65-cpsw-nuss 8000000.ethernet eth0: PHY [8000f00.mdio:00] driver [TI DP83867] (irq=POLL)
[ 34.177741] am65-cpsw-nuss 8000000.ethernet eth0: configuring for phy/rgmii-rxid link mode
[ 34.184415] am65-cpsw-nuss 8000000.ethernet eth1: PHY [8000f00.mdio:01] driver [TI DP83867] (irq=POLL)
[ 34.184425] am65-cpsw-nuss 8000000.ethernet eth1: configuring for phy/rgmii-rxid link mode
[ 34.400791] OOM killer enabled.
[ 34.403934] Restarting tasks ... done.
[ 34.408982] random: crng reseeded on system resumption
[ 34.555214] k3-m4-rproc 5000000.m4fss: Core is off in resume
[ 34.560924] remoteproc remoteproc0: powering up 5000000.m4fss
[ 34.566695] remoteproc remoteproc0: Booting fw image am62-mcu-m4f0_0-fw, size 55016
[ 34.595350] rproc-virtio rproc-virtio.2.auto: assigned reserved memory node m4f-dma-memory@9cb00000
[ 34.605831] virtio_rpmsg_bus virtio1: rpmsg host is online
[ 34.611540] rproc-virtio rproc-virtio.2.auto: registered virtio1 (type 7)
[ 34.618396] remoteproc remoteproc0: remote processor 5000000.m4fss is now up
[ 34.619659] virtio_rpmsg_bus virtio1: creating channel ti.ipc4.ping-pong addr 0xd
[ 34.633257] virtio_rpmsg_bus virtio1: creating channel rpmsg_chrdev addr 0xe
[ 34.645777] PM: suspend exit
root@am62xx-evm:~#
3.3.6.2. MCU GPIO
One of the most common ways to wakeup a system is by using some I/O activity. MCU GPIOs allow us to do this by configuring the MCU GPIO controller as a wakeup source. In ideal scenarios, the firmware running on MCU core is responsible for configuring MCU GPIO’s as a wakeup source. However, if the application design doesn’t rely too much on the MCU firmware then Linux can be used to configure the MCU GPIOs as a wakeup source. You can refer to the mcu_gpio_key node in k3-am62x-sk-lpm-wkup-sources.dtso and use it as a template to configure the MCU GPIO of your choice as a wakeup capable GPIO.
A brief guide to configuring an MCU GPIO as wakeup:
First, we add gpio-keys as a compatible string, refer to gpio_keys kernel documentation for details.
compatible = "gpio-keys";
Set the desired pinctrl,
pinctrl-names = "default";
pinctrl-0 = <&wake_mcugpio1_pins_default>;
Setup the interrupt parent and interrupt as MCU_GPIO0,
interrupt-parent = <&mcu_gpio0>;
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
Now, under the switch node we add the following:
switch {
label = "MCUGPIO";
linux,code = <143>;
gpios = <&mcu_gpio0 4 GPIO_ACTIVE_LOW>;
wakeup-source;
};
The label is the descriptive name of the key. The string will reflect under /proc/interrupts as:
root@<machine>:~# cat /proc/interrupts | grep "MCUGPIO" 273: 0 0 0 0 GPIO 4 Edge -davinci_gpio MCUGPIO
linux,code: Keycode to emit.
gpios: the gpio required to be used as the gpio-key.
The wakeup-source property describes devices which have wakeup capability.
This indicates that gpio_keys can wake-up the system from Deep Sleep or MCU Only mode.
The reason we can easily use MCU GPIOs to wakeup the system from deep sleep is because MCU GPIO’s are in a power domain that is never really shut down. This means that this domain stays ON even when the SOC is in deep sleep. Hence, the GPIO controller is able to act as a wakeup source and send a wakeup interrupt to the Device Manager. To understand the role of Device Manager please refer to S/W Architecture of System Suspend
MCU GPIO wakeup can only be tested when k3-am62x-sk-lpm-wkup-sources.dtso overlay is loaded. Please refer to How to enable DT overlays for more details.
Once the system has entered Deep Sleep or MCU Only mode as shown in the LPM section, wakeup from MCU_SPI0_D1 can be triggered by grounding Pin 4 on J8 MCU Header.
3.3.6.3. Main I/O Daisy Chain
The main domain is powered-off when the SoC enters low power mode. This includes controllers like Main UART, GPIO, I2C, etc. The question then arises how to wakeup the SoC from peripherals connected to these controllers (for example main UART)? Here’s where the role of I/O Daisy Chaining comes in. At the hardware level, all the pads in an SoC have to be pinmuxed to dedicated controllers like UART or GPIO.
For example, If a key press on Main UART (which is used for Linux console logs) were to wakeup the system from Deep Sleep then simply configuring the Main UART controller as a wakeup source wouldn’t suffice. This is because the UART controller is powered off and wouldn’t be able to register any key press as such. However, at the “pad” level we are still connected, and the pads have a specific way to be configured as wakeup sources.
For detailed information and sequence please refer to I/O Power Management and Daisy Chaining section in the TRM. To briefly explain, setting the 29th bit in the desired padconfig register, allows the pad to act as a wakeup source by triggering a wake irq to the DM R5 in Deep Sleep states.
Note
AM62x supports the ability to wakeup using pad based wake event ONLY in Deep Sleep or MCU Only Mode. During active system usage, even if the wake_enable bit is set the system will be unresponsive to any wakeup activity on that pad.
To demonstrate I/O daisy chain wakeup as part of AM62x offering, two reference examples are provided:
main_uart0 is used where a key press on the Linux console can wakeup the system.
main_gpio is used where activity on configured GPIO pin can wakeup the system.
3.3.6.3.1. Main UART
The way to configure UART as an I/O daisy chain wakeup, refer to the main_uart0 node in k3-am62x-sk-common.dtsi
interrupts-extended = <&gic500 GIC_SPI 178 IRQ_TYPE_LEVEL_HIGH>,
<&main_pmx0 0x1c8>; /* (D14) UART0_RXD PADCONFIG114 */
interrupt-names = "irq", "wakeup";
Here, we chain the IRQ to the pinctrl driver using the second interrupts-extended entry. The wake IRQ framework in Linux works in such a way that the second entry gets marked as a wakeup source, and then the pinctrl driver is informed that the pad 0x1c8 in this case is to be configured as a wakeup pad when system enters deep sleep.
To use main_uart0 as a wakeup source, ensure serial is a wake-irq in /proc/interrupts:
root@<machine>:~# grep wakeup /proc/interrupts
231: 0 0 0 0 pinctrl 456 Edge 2800000.serial:wakeup
Then, run this script:
#!/bin/bash -xe
# Detach kernel serial console
consoles=$(find /sys/bus/platform/devices/*.serial/ -name console)
for console in ${consoles}; do
echo -n N > ${console}
done
# Configure PM runtime autosuspend
uarts=$(find /sys/bus/platform/devices/*.serial/power/ -type d)
for uart in $uarts; do
echo -n 3000 > $uart/autosuspend_delay_ms
echo -n enabled > $uart/wakeup
echo -n auto > $uart/control
done
# Configure wake-up from suspend
uarts=$(find /sys/class/tty/tty[SO]*/power/ -type d 2>/dev/null)
for uart in $uarts; do
echo -n enabled > $uart/wakeup
done
This will configure UART to act as deep sleep wakeup source, and then a key press on same terminal should trigger a wakeup from Deep Sleep.
Any other pad can be chosen as per application requirements depending on which pad is required to wakeup the system.
3.3.6.3.2. Main GPIO
Configuring Main GPIO as an I/O daisy chain wakeup source requires a combination of gpio-keys with chained IRQ in the pinctrl driver. The configuration and working of these frameworks have been covered under the MCU GPIO and Main UART sections.
The reference configuration for Main GPIO wakeup can be found under gpio_key node in k3-am62x-sk-lpm-wkup-sources.dtso
Main GPIO wakeup can only be tested when k3-am62x-sk-lpm-wkup-sources.dtso overlay is loaded. Please refer to How to enable DT overlays for more details.
To use main_gpio as a wakeup source, ensure gpio is a wake-irq in /proc/interrupts:
root@<machine>:~# grep wakeup /proc/interrupts
531: 0 0 0 0 pinctrl 416 Edge WKGPIO:wakeup
Once the system has entered Deep Sleep or MCU Only mode as shown in the LPM section, wakeup from MAIN GPIO1_10 can be triggered by grounding Pin 33 on J3 User Expansion Connector.
3.3.6.4. WKUP UART
The UART in WKUP domain is capable of waking up the system from Deep Sleep and MCU Only modes.
In order to use WKUP UART as a wakeup source, it needs to be configured in a generic way using the ti-sysc interconnect target module driver. The reference configuration can be found under target-module in k3-am62-wakeup.dtsi
WKUP UART is generally available on the third serial port (/dev/ttyUSB2) and by default it only shows output from DM R5.
Once the system has entered Deep Sleep or MCU Only mode as shown in the LPM section, wakeup from WKUP UART can be triggered by doing any key press on the WKUP UART terminal. No output will be visible on the WKUP UART terminal, but Linux resume messages will be printed on the MAIN UART terminal.
3.3.6.5. USB Wakeup methods
System wakeup is possible through the USB events in both Host and Device mode.
3.3.6.5.1. Host Mode Wakeup Events
The USB wakeup events in Host mode are described below:
3.3.6.5.1.1. Wakeup via a device connect event
Follow the steps described in LPM section to put the system in Low Power Mode via Deep Sleep or MCU only method.
Now plug in a USB device to one of the port on the board and the system should wakeup. Post wakeup, the device would show up enumerated. This can be checked by below command before and after suspending and waking up the system.
# lsusb -t
3.3.6.5.1.2. Wakeup via a device disconnect event
Plug in a USB device to one of the port on the board and check that the device is enumerated by executing the below command.
# lsusb -t
Follow the steps described in LPM section to put the system in Low Power Mode via Deep Sleep or MCU only method.
Once the system is suspended, disconnect the USB device from the board and this should wakeup the system. The device will not show up in list of USB enumerated devices. This can be verified by executing
# lsusb -t
3.3.6.5.1.3. Via Remote wakeup event
Use a device that supports USB suspend/resume and ensure that the USB device can suspend and resume correctly. For a example a Logitech USB keyboard that supports suspend/resume. Follow below steps to check whether the keyboard is capable to trigger a remote wakeup event to system.
Assuming the USB keyboard device is at /sys/bus/usb/devices/1-1/, enable USB autosuspend and wakeup
# echo auto > /sys/bus/usb/devices/1-1/power/control
# echo enabled > /sys/bus/usb/devices/1-1/power/wakeup
Allow for two seconds of inactivity and check the runtime power status of the keyboard. It should show “suspended”, indicating that the keyboard has entered into suspend state.
# cat /sys/bus/usb/devices/1-1/power/runtime_status
Now press a key on the keyboard and check the runtime power status and it would come back to “active”.
# cat /sys/bus/usb/devices/1-1/power/runtime_status
Follow the steps described in LPM section to put the system in Low Power Mode via Deep Sleep or MCU only method.
And once in suspended state, trigger system wakeup via remote wakeup event by typing keys on the keyboard. The system would wakeup. And USB keyboard would still be present in the system’s list of USB enumerated devices and this can be verified by executing
# lsusb -t
3.3.6.5.2. Device Mode Wakeup Events
3.3.6.5.2.1. Wakeup via connect event
Load a USB gadget driver such as g_zero
# modprobe g_zero
Follow the steps described in LPM section to put the system in Low Power Mode via Deep Sleep or MCU only method.
Once the system has entered the suspend state, plug a cable from a different Host system to the board’s USB DRP port. This should wakeup the system and gadget will be enumerated on the Host. Enumeration of the gadget on the Host system can be verified by executing the below command on the Host system
HOST:~$ lsusb -t
3.3.6.6. MCU IPC based Wakeup
It’s possible to use IPC based wakeup events from the MCU core. For details on how to implement this from the firmware side, please refer to the relevant documentation:
To use MCU IPC based wakeup, system should be placed into MCU Only mode as shown in the LPM section.
Once the SoC enters MCU Only mode, the following log should be printed on the MCU UART (in most cases it will be /dev/ttyUSB3)
[IPC RPMSG ECHO] Next MCU mode is 1
[IPC RPMSG ECHO] Suspend request to MCU-only mode received
[IPC RPMSG ECHO] Press a single key on this terminal to resume the kernel from MCU only mode
Any key press on the same terminal should trigger a wakeup from MCU Only mode and the following message printed:
[IPC RPMSG ECHO] Main domain resumed due to MCU UART
3.3.6.7. Confirming the Wakeup event type
When the SoC wakes up from any Low Power Mode, the Device Manager logs the wake reason. This wake reason can be queried by Linux using the TISCI LPM API.
This wake reason is printed as part of the Linux suspend/resume log:
[ 37.357109] CPU3 is up
[ 37.357710] ti-sci 44043000.system-controller: ti_sci_resume: wakeup source: 0x50
In the above example, 0x50 means that WKUP_RTC0 is the wakeup source.