System suspend (A64)
System suspend is done on multiple levels, from top to bottom:
- Prepares whatever it deems necessary prior to suspend
- Triggers the suspend by writing to
- Linux kernel:
userspace processes so that they stop asking kernel to do stuff
that device drivers would need to perform
- Puts devices it controls into low
power state or shuts them down (while
keeping enough state to be able to resume them) via
- Offlines secondary CPU cores via PSCI interface to ATF
SYSTEM_SUSPENDfunction of PSCI
- Freezes userspace processes so that they stop asking kernel to do stuff
- Performs some CPU management tasks and
forwards some power management tasks to [crust firmware] running on
SCP(System Control Processor), which in Allwinner world is single core CPU implementing
OpenRISC 1000architecture called variously CPUS or ARISC in Allwinner docs.
- Performs some CPU management tasks and forwards some power management tasks to [crust firmware] running on
- shuts down the CPU cores and the entire CPU core cluster and power gates it
- turns off CPU clocks and CPU voltage regulators
- sets DRAM to self-refresh, powers down memory controller
- sets GPIO ports that will have to remain powered to hold mode (to hold their current state)
- configures PMIC for sleep mode
- disables remaining non-critical clocks, PLLs, etc.
- reconfigures bus clocks,
- turns off the main oscillator
- and so on
Management firmware (crust) then loops and watches for wakeup interrupts and restores the system into running state if necessary.
Currently crust is able to put system into a
sleep state that consumes
~110mW on PinePhone.
There are some
limits to what devices can be used for wakeup currently, because of interrupt
routing for some possible wakeup sources not going through
So on A64 volume keys can't be used for wakeup, for example.
Controlling suspend/resume from userspace
Suspended state is entered by writing into sysfs files:
# see available suspend to RAM sleep modes cat /sys/power/mem_sleep # configure one of them (in this case suspend to idle, which just idles all ARM CPUs) echo s2idle > /sys/power/mem_sleep # initiate power state change echo mem > /sys/power/state
Wakeup sources can
be listed and configured via sysfs files under
# list all enabled wakeup sources cat /sys/class/wakeup/wakeup*/name 1f00000.rtc alarmtimer axp20x-battery axp813-ac axp20x-usb 1c21800.lradc musb-hdrc.1.auto # disable a wakeup source cat /sys/class/wakeup/wakeup#/device/power/wakeup enabled echo disabled > /sys/class/wakeup/wakeup#/device/power/wakeup # enable a wakeup source (you need to find the device in sysfs first) find /sys/devices -wholename '*power/wakeup' /sys/devices/platform/soc/1c1a000.usb/usb1/power/wakeup /sys/devices/platform/soc/1c1b000.usb/usb3/power/wakeup /sys/devices/platform/soc/1c1a400.usb/usb2/power/wakeup /sys/devices/platform/soc/1c28c00.serial/tty/ttyS2/power/wakeup /sys/devices/platform/soc/1c1b400.usb/usb4/power/wakeup /sys/devices/platform/soc/1c21800.lradc/power/wakeup /sys/devices/platform/soc/1c28400.serial/serial0/power/wakeup /sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp20x-ac-power-supply/power_supply/axp813-ac/power/wakeup /sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp20x-battery-power-supply/power_supply/axp20x-battery/power/wakeup /sys/devices/platform/soc/1f03400.rsb/sunxi-rsb-3a3/axp20x-usb-power-supply/power_supply/axp20x-usb/power/wakeup /sys/devices/platform/soc/1c28000.serial/tty/ttyS0/power/wakeup /sys/devices/platform/soc/1f00000.rtc/power/wakeup /sys/devices/platform/soc/1c19000.usb/musb-hdrc.1.auto/power/wakeup /sys/devices/platform/serial8250/tty/ttyS6/power/wakeup /sys/devices/platform/serial8250/tty/ttyS4/power/wakeup /sys/devices/platform/serial8250/tty/ttyS7/power/wakeup /sys/devices/platform/serial8250/tty/ttyS5/power/wakeup /sys/devices/platform/serial8250/tty/ttyS3/power/wakeup # enable wakeup source (volume key press in this case) echo enabled > /sys/devices/platform/soc/1c21800.lradc/power/wakeup