An Overview of Generic Power Domains (genpd) on Linux

Power management core hierarchy diagram

The saying goes that most programming problems can be solved with another layer of abstraction. Generic Power domains (genpd) are a (relatively) new Linux kernel power management abstraction that model the way power is controlled for components on SoCs. In other words, genpd describes the relationship between devices and power controllers. Generic power domains allow these relationships to be declared outside of device drivers, which means these device groups can be updated at runtime.

Static versus Dynamic power management

Linux supports two types of idle power management: static and dynamic. Static power management is the term for suspend and resume operations; it controls system-wide power. This is the traditional way to suspend a system and comes from the original support for laptop PCs where the whole system would be suspended at once. A good example of this is closing the laptop lid.

Dynamic power management, on the other hand, controls power to individual devices, allowing flexible power management based on activity in different parts of the SoC/platform.

Dynamic power management for device drivers is implemented inside of the kernel with the runtime PM framework (dynamic power management for CPUs is handled differently, via the CPUfreq and CPUidle subsystems). Device drivers use the struct dev_pm_ops data object to hook up their callbacks:

These callbacks allow devices to be powered up or down, or enter a low-power idle state when they go idle, such as when a transaction is finished. Each individual driver decides when the device is idle.

Device drivers can inform the PM core when devices are going idle. Idleness is controlled using the pm_runtime_get() and pm_runtime_put() functions. This API maintains a reference counter for each device to track whether the device is in-use at any time. pm_runtime_get() blocks the device from entering a low-power mode until the last pm_runtime_put().

But controlling power on a per-device level, while better than system-wide, isn’t the most efficient way to save power. Instead, hardware vendors have long provided a way to control power to groups of devices through power islands, or power domains.

 

What are power domains?

Devices and SoCs have separate power rails with devices connected to them. Power domains are a hardware concept for managing devices sharing power rails. Their power voltages are correlated. While the hardware power islands have existed for many years, the kernel has only recently added support for them.

Linux power domain drivers sit above devices in the PM hierarchy, at the same level as bus_type.

Power management core hierarchy diagram

These relationships need to be modeled inside of the kernel because the same IP blocks and chip families might have different groups depending on the hardware. For example, the same ARM IP can be used in different SoC vendor products and they might group things differently. So you need a way to describe this fixed relationship. Some examples are whether all CPUs/clusters share a power rail or have independent rails, or whether video-centric IP shares a power rail with the display IP.

A solution is needed that abstracts this so that the driver doesn’t need to care. And these power domain relationships need to be described in a way that does not require updating drivers for every new platform and configuration.

Crucially, we don’t want a driver to care whether it’s running on an AmLogic or Qualcomm chip — it should work on both, independent of how the power rails are configured on those platforms.

 

Generic Power Domains (genpd)

Generic power domains are an abstraction on top of Linux kernel power domains. They provide a number of benefits over regular power domains because they support:

  • Domain hierarchies
  • Adding and removing devices from domains at runtime
  • Power governors
  • Device Tree support

Generic power domain drivers control the entire domain’s power when an entire group of devices goes idle. A typical action is sending a command to a microcontroller or writing to a register to disable a voltage rail. The genpd framework takes care of running the callbacks for every genpd driver in a hierarchy, a feature that makes it possible to control the nested power domains available on some SoCs.

genpd drivers can be both IRQ-safe and always-on. The former (enabled with the GENPD_FLAG_IRQ_SAFE) is useful for domains that can be powered on/off in atomic context. This feature is particularly useful for devices that have low suspend and resume latency, and can be powered on or off quickly.

Always-on genpd drivers make sense if you have devices that must not be powered off. For example, CPUs that are behind a power microcontroller. Whether or not genpd drivers set the GENPD_FLAG_ALWAYS_ON flag can be platform-dependent.

In addition, there are optional driver callbacks that can be used if drivers want to know when new devices are attached or detached from a generic power domain. These callbacks are used to execute power domain-specific actions.

Generic power domains are described in the device tree, so the configuration can be described on a per-platform basis. Storing the configuration data inside device tree also makes it easy to update since the genpd driver requires no changes when new SoCs are released; a single driver can support all platform configurations.

Here’s a simple genpd example:

Here’s how it would be used by a device:

genpd also provides governors which add another level of control in between the PM core and the device drivers. Every generic power domain can have its own governor. Governors decide whether power should be gated to a generic power domain, and their decisions are based on simple heuristics. There are two available in the kernel: the simple QoS governor and the always-on governor.

As the name implies, the always-on governor prevents devices from being powered off. The simple QoS governor is more interesting — it considers the time it takes to power devices on and off, known as suspend and resume latency. If a power domain is predicted to be resumed before power can be turned off to all devices, the simple QoS governor will prevent the power domain from suspending.

Governors have a standard plugin-architecture, so you can write custom versions for specific platforms as well.

 

Performance states

A recent addition to the kernel, in v4.15, is support for power domain performance states. This new feature makes it possible to finely tune the power consumption of devices by varying the voltage to power rails. genpd drivers implement this with the (*set_performance_state) callback. Sadly, there are no upstream users of this API yet, but one is currently being reviewed on the kernel mailing lists.

 

Resources

The genpd framework provides an extremely flexible API for finely controlling power domains. If you want to learn more, here is a list of resources:

And here’s the video of Kevin’s talk on generic power domains at Kernel Recipes 2017.