Zynq UltraScale+ MPSoC Power Management - Linux Kernel

This page provides tips and examples of Linux kernel power management solutions for the Zynq UltraScale+ MPSoC.

Prerequisites

  1. You have installed Petalinux 2017.1.
  2. You have created a Petalinux project using the BSP for your board.
  3. You were able to boot the pre-built images on your board.

System PM

Suspend

The kernel is suspended when the CPU and most of the peripherals are powered down. The system run states needed to resume from suspend is stored in the DRAM, which is put into self-refresh mode.

The required kernel configuration option settings are:
  • Power management options
    • [*] Suspend to RAM and standby
    • [*] User space wakeup sources interface
    • [*] Device power management core functionality

  • Device Drivers
    • SOC (System On Chip) specific Drivers
      • [*] Xilinx Zynq MPSoC driver support
        • [*] Enable Zynq MPSoC generic PM domains


Type the following command to suspend the kernel. (Note: you must enable a wake-up source first otherwise the kernel will never resume.)
$ echo mem > /sys/power/state

Wake-up Source

The kernel resumes from the suspend mode when a wake-up event occurs.

UART

To wake up the APU on UART input:
$ echo enabled > /sys/devices/platform/amba/ff000000.serial/tty/ttyPS0/power/wakeup

GPIO

The required kernel configuration options are:
  • Device Drivers
    • [*] GPIO Support
      • [*] /sys/class/gpio/... (sysfs interface)
      • Memory mapped GPIO drivers
        • [*] Xilinx GPIO support
        • [*] Xilinx Zynq GPIO support

To wake up the APU on the GPIO pin:
$ echo enabled > /sys/devices/platform/gpio-keys/power/wakeup

RTC

The required kernel configuration options are:
  • Device Drivers
    • Real Time Clock
      • [*] Xilinx Zynq Ultrascale+ MPSoC RTC

To wake up the RTC to wake up the APU after 10 seconds:
$ echo +10 > /sys/class/rtc/rtc0/wakealarm

CPU PM

CPU Hotplug

Kernel documentation: <Linux source>/Documentation/power/suspend-and-cpuhotplug.txt


The required kernel configuration options are:
  • Kernel Features
    • [*] Support for hot-pluggable CPUs
  • Power management options
    • [*] Suspend to RAM and standby

The user may take one or more APU cores on-line and off-line as needed via the CPU Hotplug control interface.

For example, to take CPU3 off-line:
$ echo 0 > /sys/devices/system/cpu/cpu3/online

CPU Idle

CPU cores are powered off when they are idling.

Kernel documentation: <Linux source>/Documentation/cpuidle/*.txt

The required kernel configuration options are:
  • CPU Power Management
    • CPU Idle
      • [*] CPU idle PM support
      • [*] Ladder governor (for periodic timer tick)
      • ARM CPU Idle Drivers
        • [*] Generic ARM/ARM64 CPU idle Driver

Below is the sysfs interface for cpuidle.
$ ls -lR /sys/devices/system/cpu/cpu0/cpuidle/
/sys/devices/system/cpu/cpu0/cpuidle/:
drwxr-xr-x    2 root     root             0 Jun 10 21:55 state0
drwxr-xr-x    2 root     root             0 Jun 10 21:55 state1
 
/sys/devices/system/cpu/cpu0/cpuidle/state0:
-r--r--r--    1 root     root          4096 Jun 10 21:55 desc
-rw-r--r--    1 root     root          4096 Jun 10 21:55 disable
-r--r--r--    1 root     root          4096 Jun 10 21:55 latency
-r--r--r--    1 root     root          4096 Jun 10 21:55 name
-r--r--r--    1 root     root          4096 Jun 10 21:55 power
-r--r--r--    1 root     root          4096 Jun 10 21:55 residency
-r--r--r--    1 root     root          4096 Jun 10 21:55 time
-r--r--r--    1 root     root          4096 Jun 10 21:55 usage
 
/sys/devices/system/cpu/cpu0/cpuidle/state1:
-r--r--r--    1 root     root          4096 Jun 10 21:55 desc
-rw-r--r--    1 root     root          4096 Jun 10 21:55 disable
-r--r--r--    1 root     root          4096 Jun 10 21:55 latency
-r--r--r--    1 root     root          4096 Jun 10 21:55 name
-r--r--r--    1 root     root          4096 Jun 10 21:55 power
-r--r--r--    1 root     root          4096 Jun 10 21:55 residency
-r--r--r--    1 root     root          4096 Jun 10 21:55 time
-r--r--r--    1 root     root          4096 Jun 10 21:55 usage
where,
  • desc : Small description about the idle state (string)
  • disable : Option to disable this idle state (bool) -> see note below
  • latency : Latency to exit out of this idle state (in microseconds)
  • name : Name of the idle state (string)
  • power : Power consumed while in this idle state (in milliwatts)
  • time : Total time spent in this idle state (in microseconds)
  • usage : Number of times this state was entered (count)

Below is the sysfs interface for cpuidle governors.
$ ls -lR /sys/devices/system/cpu/cpuidle/
/sys/devices/system/cpu/cpuidle/:
-r--r--r--    1 root     root          4096 Jun 10 21:55 current_driver
-r--r--r--    1 root     root          4096 Jun 10 21:55 current_governor_ro

CPU Frequency

Adjust CPU frequency at runtime.

Kernel documentation: <Linux source>/Documentation/cpu-freq/*.txt

The required kernel configuration options are:
  • CPU Power Management
    • CPU Frequency scaling
      • [*] CPU Frequency scaling
        • Default CPUFreq governor
          • Userspace
        • <*> Generic DT based cpufreq driver

Read current CPU frequency (same for all cores):
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

Look up the available governors speeds (same for all cores):
$ cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_available_governors

Select the 'userspace' governor for CPU frequency control (same for all cores):
$ echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

Look up the available CPU speeds (same for all cores):
$ cat /sys/devices/system/cpu/cpu1/cpufreq/scaling_available_frequencies
 

Change the CPU speed (same for all cores):
$ echo <frequency> > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed

Global Storage Registers

Global General Storage Registers

Four 32-bit storage registers are available for general use. Their values are not preserved across after software reboots.
Device Node
MMIO Register
MMIO Access
Valid Value Range
/sys/devices/platform/firmware/ggs0
GLOBAL_GEN_STORAGE0
0xFFD80030
0x00000000 - 0xFFFFFFFF
/sys/devices/platform/firmware/ggs1
GLOBAL_GEN_STORAGE1
0xFFD80034
0x00000000 - 0xFFFFFFFF
/sys/devices/platform/firmware/ggs2
GLOBAL_GEN_STORAGE2
0xFFD80038
0x00000000 - 0xFFFFFFFF
/sys/devices/platform/firmware/ggs3
GLOBAL_GEN_STORAGE3
0xFFD8003C
0x00000000 - 0xFFFFFFFF
Read the value of a global storage register:
$ cat /sys/devices/platform/firmware/ggs0
Write the mask and value of a global storage register:
$ echo 0xFFFFFFFF 0x1234ABCD > /sys/devices/platform/firmware/ggs0

Persistent Global General Storage Registers

Four 32-bit persistent global storage registers are available for general use. Their values are preserved across after software reboots.
Device Name
MMIO Register
MMIO Access
Valid Value Range
/sys/devices/platform/firmware/pggs0
PERS_GLOB_GEN_STORAGE0
0xFFD80050
0x00000000 - 0xFFFFFFFF
/sys/devices/platform/firmware/pggs1
PERS_GLOB_GEN_STORAGE1
0xFFD80054
0x00000000 - 0xFFFFFFFF
/sys/devices/platform/firmware/pggs2
PERS_GLOB_GEN_STORAGE2
0xFFD80058
0x00000000 - 0xFFFFFFFF
/sys/devices/platform/firmware/pggs3
PERS_GLOB_GEN_STORAGE3
0xFFD8005C
0x00000000 - 0xFFFFFFFF
Read the value of a persistent global storage register:
$ cat /sys/devices/platform/firmware/pggs0
Write the mask and value of a persistent global storage register:
$ echo 0xFFFFFFFF 0x1234ABCD > /sys/devices/platform/firmware/pggs0

Debugfs

The debugfs interface is intended for testing and debugging the integration between the Linux kernel and the Zynq UltraScale+ MPSoC power management framework. This interface must be used with a lot of care. In fact, accessing this interface during normal PM operation will very likely cause unexpected problems. Please refer to UG1199 for the usage of PM API.

The required kernel configuration options are (in this order):
  • Power management options
    • [*] Suspend to RAM and standby
    • [*] User space wakeup sources interface
    • [*] Device power management core functionality

  • Kernel hacking
    • Compile-time checks and compiler options
      • [*] Debug Filesystem

  • Device Drivers
    • SOC (System On Chip) specific Drivers
      • [*] Enable Xilinx Zynq MPSoC Power Management API debugfs functionality
      • [*] Xilinx Zynq MPSoC driver support


Access to the debugfs interface is provided through the following node in the sysfs:
/sys/kernel/debug/zynqmp_pm/power
For example,
$ echo request_node 22 1 100 1 > /sys/kernel/debug/zynqmp_pm/power
See UG1199 for the input parameters to the APIs.

Get API Version

Get the API version.
$ echo get_api_version > /sys/kernel/debug/zynqmp_pm/power

Request Suspend

Request another PU to suspend itself.
$ echo request_suspend <node> > /sys/kernel/debug/zynqmp_pm/power

Self Suspend

Notify PMU that this PU is about to suspend itself.
$ echo self_suspend <node> /sys/kernel/debug/zynqmp_pm/power

Force Power Down

Force another PU to power down.
$ echo force_powerdown <node> > /sys/kernel/debug/zynqmp_pm/power

Abort Suspend

Notify PMU that the attempt to suspend has been aborted.
$ echo abort_suspend > /sys/kernel/debug/zynqmp_pm/power

Request Wake-up

Request another PU to wake up from suspend state.
$ echo request_wakeup <node> <set_address> <address> > /sys/kernel/debug/zynqmp_pm/power

Set Wake-up Source

Set up a node as the wake-up source.
$ echo set_wakeup_source <target> <wkup_node> <enable> > /sys/kernel/debug/zynqmp_pm/power

System Shutdown

Shut down the PU's own sub-system.
$ echo system_shutdown <action> <scope> > /sys/kernel/debug/zynqmp_pm/power
Action:
  • 0: Shutdown
  • 1: Reset
  • 2: Set reset scope
Scope:
  • 0: APU
  • 1: PS
  • 2: System

Request Node

Request to use a node.
$ echo request_node <node> > /sys/kernel/debug/zynqmp_pm/power

Release Node

Free a node that is no longer being used.
$ echo release_node <node> > /sys/kernel/debug/zynqmp_pm/power

Set Requirement

Set the power requirement on the node.
$ echo set_requirement <node> <capabilities> > /sys/kernel/debug/zynqmp_pm/power

Set Max Latency

Set the maximum wake-up latency requirement for a node.
$ echo set_max_latency <node> <latency> > /sys/kernel/debug/zynqmp_pm/power

Get Node Status

Get status information of a node. (Any PU can check the status of any node, regardless of the node assignment.)
$ echo get_node_status <node> > /sys/kernel/debug/zynqmp_pm/power
Returns (printed to screen):
  • Status: Node power status (see below.)
  • Usage: The master(s) using this node (bit-map):
    • Bit 0: Used by this master
    • Bit 1: Used by other master(s)
  • Requirement: Capabilities required (bit-map):
    • Bit 0: PM_CAP_ACCESS
    • Bit 1: PM_CAP_CONTEXT
    • Bit 2: PM_CAP_WAKEUP
Status
Node Type
0
1
2
3
Memory
PM_SRAM_STATE_OFF
PM_SRAM_STATE_RET
PM_SRAM_STATE_ON

CPU PP
PM_GPP_SLAVE_STATE_OFF
PM_GPP_SLAVE_STATE_ON


Processor
PM_PROC_STATE_FORCEDOFF
PM_PROC_STATE_ACTIVE
PM_PROC_STATE_SLEEP
PM_PROC_STATE_SUSPENDING
Other Nodes
PM_PWR_STATE_OFF
PM_PWR_STATE_ON


Get Operating Characteristic

Get operating characteristic information of a node.
$ echo get_operating_characteristic <node> > /sys/kernel/debug/zynqmp_pm/power

Reset Assert

Assert/de-assert on specific reset lines.
$ echo reset_assert <reset> <action> > /sys/kernel/debug/zynqmp_pm/power

Reset Get Status

$ echo reset_get_status <reset> > /sys/kernel/debug/zynqmp_pm/power

MMIO Read

$ echo mmio_read <address> > /sys/kernel/debug/zynqmp_pm/power
Address is in hex format (e.g. 0xFFFF0000). Not all addresses are accessible by all masters.

MMIO Write

$ echo mmio_write <mask> <address> <value> > /sys/kernel/debug/zynqmp_pm/power
Mask, address and value are in hex format (e.g. 0xFFFF0000). Not all addresses are accessible by all masters.

Related Links