[Rev 1.2 - Added a parameter to .suspend() and .resume() functions
indicating the power policy used by the PMA. This parameter will help
driver take policy based optimized actions. Described in detail at the
end]
[Revised v1.1 incorporating feedbacks. The changes are shown at the
end]
Problem Statement:
Not all Zephyr kernel drivers provide the same interfaces.
Why this is a problem:
-----------------------------
The Zephyr kernel currently has devices that are essential for core OS
functions (such as APICs and timers), but provide no public API means
for accessing them. Without any consistent method to access device
drivers on the platform, it becomes very difficult to achieve power
targets.
What should be done:
-----------------------------
1) Each native Zephyr kernel driver and shim driver (such as QMSI) shall
support:
a) uint32_t suspend() - routine that will move any required device state
data
to RAM* with the following valid return values:
- DEV_OK
- DEV_BUSY
- DEV_FAIL
b) uint32_t resume() - routine that will retrieve any device state data
from
RAM* with the following valid return values:
- DEV_OK
- DEV_FAIL
2) Provide a name recognized by the device_get_binding() function, this
includes what are currently thought to be drivers such as timers,
IOAPIC, and LOAPIC.
*The power management process is not expected to power down system RAM
(it will most likely stay in selective suspend).
The size of the device data is dependent upon an individual device, and
therefore the system integrator must be wary of the number of devices
being utilized.
Device suspend flow:
Device Drivers at suspend shall:
- Device state shall be saved to memory and maintained across a PM event
- Turning off the device clock
- Return appropriate error code
Device resume flow:
Device Drivers at resume shall:
- Restore to state saved in memory
- Turn on the device clock
- Return appropriate error code
The drivers may skip the saving/restoring and device re-initialization
steps, if the power policy used by the PMA is not expected to cause the
devices to lose state.
Device domain experts will be needed to implement the proper methods for
suspending and resuming each device.
----New additions-------
Following 2 macros would be added to allow device drivers to implement
the .suspend() and .resume() hooks described in #1 above.
A device ops structure holds the .suspend() and .resume() which is
included inside each device's device structure:
struct device_ops example_dev_ops = {
.suspend = example_suspend,
.resume = example_resume
};
Two new macros would be created that drivers use instead of DEVICE_INIT
and SYS_INIT if they implement the .suspend and .resume functions. For
devices using non-PM macros, a default dev_ops will be assigned that
does nothing (so app need not check if dev_ops != NULL).
a) DEVICE_INIT_PM(dev_name, drv_name, init_fn, &example_dev_ops, data,
cfg_info, level, prio);
b) SYS_INIT_PM(name, init_fn, &example_dev_ops, level, prio);
SYS_INIT_PM also added the "name" argument so PMA can call
the .suspend/.resume for devices like APICs that need to do
suspend/resume operations. The methods that retrieve the pointer to the
device structure of any device requires the device to be assigned a name
unlike the SYS_INIT macro which assigns a "" as the name for devices.
All this will be inside DEVICE_POWER_MANAGEMENT Kconfig flag.
----Rev 1.2 changes-------
The .suspend and .resume functions described in #1 would be passed a
parameter indicating the policy used by the PMA. Depending on the
policy, the driver may take different actions during .suspend
and .resume calls. This is because, unless the policy causes the
devices to lose state, the device driver need not save/restore state.
This helps reduce wake latency in states that do not need save/restore
and reinitialization of devices.
The policies described in RFC 5/5 in detail are listed below:
1. PM_SOC_LPS - Devices do not lose state
2. PM_SOC_DS - Devices may lose state
3. PM_SOC_DEVICE_SUSPEND_ONLY - Devices do not lose state