diff --git a/doc/subsystems/power_management.rst b/doc/subsystems/power_management.rst index af1f34dfed1..2b533d7b1b4 100644 --- a/doc/subsystems/power_management.rst +++ b/doc/subsystems/power_management.rst @@ -4,212 +4,252 @@ Power Management ################ The power management infrastructure consists of interfaces exported by the -power management subsystem for a Power Manager application to implement power +power management subsystem. This subsystem exports interfaces that a +:abbr:`Power Management Application (PMA)` uses to implement power management policies. Terminology *********** -`PMA` - Shortened form for Power Manager Application, the system integrator - provided application that maintains any power management policies and - enforces power management actions based on them. This would be integrated - into the main Zephyr application. +:dfn:`PMA` -`LPS` - Any of the CPU low power states supported by the processor. + The system integrator provides the :abbr:`PMA (Power Manager + Application)`. The PMA maintains any power management policies and + executes the power management actions based on those policies. + The PMA must be integrated into the main Zephyr application. -`SoC Power State` - Power state implemented at the SoC level which includes processor and - device power state. +:dfn:`LPS` -`Hook function` - A callback function implemented by one component and called by another - component. e.g. functions implemented by PMA that can be called by the - kernel. + :abbr:`LPS (Low Power States)` refers to any one of the low power states supported by the CPU. -**Architecture and SoC dependent Power States:** +:dfn:`SoC Power State` + + An SoC Power State describes processor and device power statuses + implemented at the SoC level. + +:dfn:`Hook function` + + A Hook function is a callback function that one component implements and + another component calls. For example, the PMA implements functions that + the kernel calls. + +Architecture and SoC dependent Power States: +============================================ + +On x86: +------- + + `Active` + The CPU is active and running in the hardware defined C0 C-state. + + `Idle` + The CPU is not active but continues to be powered. + The CPU may be in one of any lower C-states: C1, C2, etc. + + `Deep Sleep` + The Power is off to the processor and system clock. RAM is retained. + +On ARM +------ -**On x86:** `Active` - The CPU is currently active and running in the hardware defined - C0 + The CPU is active and running. + `Idle` - The CPU is not currently active, and continues to be powered - on. The CPU may be in one of any lower C-states (i.e. C1, C2, etc). - `Deep Sleep` - Power to the processor and system clock turned off. RAM - retained. -**On ARM:** - `Active` - The CPU is currently active and running - `Idle` - Stops the processor clock. The ARM documentation describes - this as Sleep. + Stops the processor clock. The ARM documentation describes + this as *Sleep*. + `Deep Sleep` Stops the system clock and switches off the PLL and flash - memory. RAM retained. -**On ARC:** + memory. RAM is retained. + +On ARC +------ + `Active` The CPU is currently active and running in the SS0 state. + `Idle` - Defined as the SS1, SS2 states. - -.. note:: - These power states are generic terms that map to the power states commonly - supported by processors and SoCs based on the 3 architectures. The PMA - writer should refer to the data sheet of the SoC to get details of each - power state. + Defined as the SS1 and SS2 states. +The power states described here are generic terms that map to the power +states commonly supported by processors and SoCs based on the three +architectures. When coding a PMA, please refer to the data sheet of the SoC +to get details on each power state. Overview ******** -The Zephyr power management subsystem provides interfaces for a system -integrator to utilize and create their own Power Management Application (PMA) -that can enforce any policies needed. It is based on the philosophy of not -enforcing any policies in the kernel and thus giving full flexibility to the -PMA. -This will be accomplished by providing an infrastructure that has an -architecture independent interface. The Zephyr kernel will provide -notification methods in both the Microkernel and Nanokernel for the PMA when -the OS is about to enter and exit system idle. The PMA will do various power -management policy enforcement operations during these notifications. +The Zephyr power management subsystem provides interfaces that a system +integrator can use to create a PMA. The PMA then enforces any policies +needed. The design is based on the philosophy of not enforcing any policies +in the kernel giving full flexibility to the PMA. + +The provided infrastructure has an architecture independent interface. Both +the microkernel and nanokernel notify the PMA when the kernel is about to +enter or exit a system idle state. The PMA can perform the power management +policy operations during these notifications. Policies ******** -When the Power Management subsystem notifies the PMA that the kernel is about -to enter system idle, it would specify a time period that it intends to idle. -This time period is the alloted time for the PMA to do any power management -operations. The PMA has the choice to do various operations, like putting the -processor or SoC in low power states, turning off some or all peripherals and -gating device clocks. Using various combinations of these operations, the PMA -would create fine grain custom power management policies. These fine grain -policies would be characterized by different levels of power savings and -different wake latencies. Generally, the operations that save more power have -a higher wake latency. While making policy decisions, the PMA would choose the -policy that would save the most power and at the same time, its total -execution time fits well within the idle time allotted by the Power Management -subsystem. -The Zephyr Power Management subsystem classifies policies into categories based -on relative power savings and the corresponding wake latencies. These also -loosely map to common power states supported by processors and SoCs in the -supported architectures. The PMA should map its fine grain custom policies to -the policy categories defined by the Power Management subsystem listed below. +When the power management subsystem notifies the PMA that the kernel is about +to enter a system idle state, it specifies the period of time the system +intends to stay idle. The PMA performs any power management operations during +this time. The PMA can perform various operations. For example, put the +processor or the SoC in a low power state, turn off some or all of the +peripherals, and gate device clocks. Using combinations of these operations, +the PMA can create fine grain custom power management policies. + +Different levels of power savings and different wake latencies characterize +these fine grain policies. In general, operations that save more power have a +higher wake latency. When making policy decisions, the PMA chooses the +policy that saves the most power. At the same time, the policy's total +execution time must fit well within the idle time allotted by the power +management subsystem. + +The Zephyr power management subsystem classifies policies into categories +based on relative power savings and the corresponding wake latencies. These +policies also loosely map to common processor and SoC power states in the +supported architectures. The PMA should map the fine grain custom policies to +the policy categories of the power management subsystem. The power management +subsystem defines three categories: + +* SYS_PM_LOW_POWER_STATE +* SYS_PM_DEEP_SLEEP +* SYS_PM_DEVICE_SUSPEND_ONLY SYS_PM_LOW_POWER_STATE ====================== -In this policy category, the PMA would do power management operations on some -or all devices and put the processor into a low power state. The device power -management operations may involve turning off peripherals and gating device -clocks. If any of those operations result in the device registers losing -state, then those states would need to be saved and restored. The PMA should -map fine grain policies to this category, with relatively less wake latency -than those that it maps to `SYS_PM_DEEP_SLEEP`_ category. The exit from this -policy is from an external interrupt, a wake up event set by the PMA or when -the idle time alloted by the Power Management subsystem expires. + +In this policy category, the PMA performs power management operations on some +or all devices and puts the processor into a low power state. The device +power management operations can involve turning off peripherals and gating +device clocks. When any of those operations causes the device registers to +lose their state, then those states must be saved and restored. The PMA +should map fine grain policies with relatively less wake latency to this +category. Policies with larger wake latency should be mapped to the +`SYS_PM_DEEP_SLEEP`_ category. Policies in this category exit from an +external interrupt, a wake up event set by the PMA, or when the idle time +alloted by the power management subsystem expires. SYS_PM_DEEP_SLEEP ================= -In this policy category, the PMA would put the system into the deep sleep -category of power states supported by SoCs. In this state, the system clock -would be turned off. The processor is turned off and would lose state. RAM is -expected to be retained and can be used to save and restore processor states. -Depending on the SoC, selected devices would also be turned off in the deep -sleep power state. Since this would cause device registers to lose state, they -would need to be saved and restored. The PMA should map fine grain policies -with the highest wake latency to this policy category. The exit from this -policy is from SoC dependent wake events. + +In this policy category, the PMA puts the system into the deep sleep power +states supported by SoCs. In this state, the system clock is turned off. The +processor is turned off and loses its state. RAM is expected to be retained +and can save and restore processor states. Only the devices necessary to wake +up the system from the deep sleep power state stay on. The SoC turns off the +power to all other devices. Since this causes device registers to lose their +state, they must be saved and restored. The PMA should map fine grain +policies with the highest wake latency to this policy category. Policies in +this category exit from SoC dependent wake events. SYS_PM_DEVICE_SUSPEND_ONLY ========================== -In this policy category, the PMA would do power management operations on some -devices but would not do any operations that would result in a processor or -SoC power state transition. The PMA should map its fine grain policies that have -the least wake latency to this category. Exit from this policy is from an -external interrupt or when the idle time alloted by the Power Management -subsystem expires. -.. note:: +In this policy category, the PMA performs power management operations on some +devices but none that result in a processor or SoC power state transition. +The PMA should map its fine grain policies that have the lowest wake latency +to this policy category. Policies in this category exit from an external +interrupt or when the idle time alloted by the power management subsystem +expires. - Some of the policy categories are named similar to the processor or SoC power - state that it is associated with. e.g. :c:macro:`SYS_PM_DEEP_SLEEP`. However, - they should be seen as policy categories and are not intended to indicate any - specific processor or SoC power state by itself. +Some policy categories names are similar to the power states of processors or +SoCs, for example, :code:`SYS_PM_DEEP_SLEEP`. However, they must be seen +as policy categories and do not indicate any specific processor or SoC power +state by themselves. + +.. _pm_hook_infra: Power Management Hook Infrastructure ************************************ -This consists of hook functions that would be implemented by the PMA and would -be called by the power management subsystem when the kernel enters and exits -idle state i.e. when it has nothing to schedule. This section will give a -general overview and concepts of the hook functions. Refer to -:ref:`Power Management APIs ` for detailed description -of the APIs. + +This infrastructure consists of the hook functions that the PMA implemented. +The power management subsystem calls these hook functions when the kernel +enters and exits the idle state, in other words, when the kernel has nothing +to schedule. This section provides a general overview and general concepts of +the hook functions. Refer to :ref:`power_management_api` for the detailed +description of the APIs. Suspend Hook function ===================== + .. code-block:: c int _sys_soc_suspend(int32_t ticks); -When kernel is about to go idle, the kernel itself will disable interrupts. The -kernel will then call the :c:func:`_sys_soc_suspend()` function, notifying the -PMA of the operation. Included in the notification are the maximum number of -ticks that the system can be set idle for. The PMA will then determine what -policies can be executed within the allotted time frame. +When the kernel is about to go idle, the power management subsystem calls the +:code:`_sys_soc_suspend()` function, notifying the PMA that the kernel is +ready to enter the idle state. -The kernel expects the :c:func:`_sys_soc_suspend()` to return one of the -following values based on the policy operation the PMA executed: +At this point, the kernel has disabled interrupts and computed the maximum +number of ticks the system can remain idle. The function passes the time that +the system can remain idle to the PMA along with the notification. When +notified, the PMA selects and executes one of the fine grain power policies +that can be executed within the allotted time. -`SYS_PM_NOT_HANDLED` - No PM operations. Indicating the PMA was not able to accomplish any - action in the time allotted by the kernel. +The power management subsystem expects the :code:`_sys_soc_suspend()` to +return one of the following values based on the power management operations +the PMA executed: -`SYS_PM_DEVICE_SUSPEND_ONLY` - Only Devices are suspended. Indicating that the PMA has accomplished - any device suspend operations. This does not include any CPU or SOC power - operations. +:code:`SYS_PM_NOT_HANDLED` -`SYS_PM_LOW_POWER_STATE` - Low Power State. Indicating that the PMA was successful at putting the - CPU into a low power state. + No power management operations. Indicates that the PMA could not + accomplish any actions in the time allotted by the kernel. -`SYS_PM_DEEP_SLEEP` - Deep Sleep. Indicating that the PMA was successful at pushing the SOC - into the Deep Sleep state. +:code:`SYS_PM_DEVICE_SUSPEND_ONLY` + + Only devices are suspended. Indicates that the PMA could accomplish any + device suspend operations. These operations do not include any processor + or SOC power operations. + +:code:`SYS_PM_LOW_POWER_STATE` + + Entered a LPS. Indicates that the PMA could put the processor into a low + power state. + +:code:`SYS_PM_DEEP_SLEEP` + + Entered deep sleep. Indicates that the PMA could put the SoC in a deep + sleep state. Resume Hook function ==================== + .. code-block:: c void _sys_soc_resume(void); -This hook function will be called by the kernel when exiting from idle state or -from the low power state the PMA put the processor and SoC in. Based on the -policy executed by the PMA in :c:func:`_sys_soc_suspend()`, it should do the -necessary recovery operations in this function. +The kernel calls this hook function when exiting from an idle state or a low +power state. Based on which policy the PMA executed in the +:code:`_sys_soc_suspend()` function, the PMA performs the necessary recovery +operations in this hook function. -.. note:: - Since the hook functions are called with interrupts disabled, the PMA should - ensure that it completes operations quick so that the kernel's scheduling - performance is not disrupted. +Since the hook functions are called with the interrupts disabled, the PMA +should ensure that its operations are completed quickly. Thus, the PMA +ensures that the kernel's scheduling performance is not disrupted. Device Power Management Infrastructure ************************************** -This infrastructure consists of interfaces into the Zephyr device model which -enables the PMA to do suspend and resume operations on devices. Refer to -:ref:`Power Management APIs ` for detailed description of -the APIs. + +The device power management infrastructure consists of interfaces to the +Zephyr device model. These interfaces enable the PMA to suspend and resume +operations on devices. Refer to :ref:`power_management_api` for detailed +description of the APIs. Device Power Management Operations ================================== -Drivers would implement handlers for suspend and resume power management -operations. PMA would call each of the drivers suspend and resume handler -functions to do the necessary power management operations on those devices. -Device PM Operations structure ------------------------------- +Drivers can implement handlers to suspend and resume power management +operations. The PMA performs the necessary power management operations on the +devices by calling each of the suspend and resume handler functions of the +drivers. + +Operations Structure +-------------------- + .. code-block:: c struct device_pm_ops { @@ -218,353 +258,361 @@ Device PM Operations structure }; This structure contains pointers to the :c:func:`suspend()` and -:c:func:`resume()` handler functions. The device driver should initialize -those pointers with the corresponding handler functions that is implemented in -the driver. +:c:func:`resume()` handler functions. The device driver initializes those +pointers with the corresponding handler functions implemented in the +driver. -Default Initializer function for PM ops ---------------------------------------- -If the driver does not implement any of of the operations then it can -initialize the corresponding pointer with the following function that does -nothing. This function should be used instead of the driver implementing its -own dummy function to avoid wasting code memory. +Default Initializer Function +---------------------------- .. code-block:: c int device_pm_nop(struct device *unused_device, int unused_policy); -Device Suspend Operation Handler function +When the driver does not implement any operations, the driver can initialize +the corresponding pointer with this function. This default initializer +function does nothing and should be used instead of implementing a dummy +function in the driver to avoid wasting code memory. + +.. _dev_suspend_handler: + +Device Suspend Operation Handler Function ----------------------------------------- + .. code-block:: c int suspend(struct device *device, int pm_policy); -This function is implemented by the device driver to perform suspend operations -on the devices it handles. The PMA would call it passing the power policy it -is currently executing. The device driver would do operations necessary to -handle the transitions associated with the policy specified by the PMA. -Example operations that the device driver would do are: +The device driver implements this function to perform the suspend operations +on the handled devices. The PMA calls the function and passes the power +policy to execute. The device driver performs the operations necessary to +handle the transitions associated with the policy the PMA specified. Here are +some example operations that the device driver performs: -- Save device states +* Save device states. -- Gate clocks +* Gate clocks. -- Turn off peripherals +* Turn off peripherals. -It would return 0 if successful. In all other cases it would return an -appropriate negative :c:macro:`errno` value. +This function returns 0 if successful. Otherwise, the function returns an +appropriate negative `errno` value. +.. _dev_resume_handler: -Device Resume Operation Handler function +Device Resume Operation Handler Function ---------------------------------------- + .. code-block:: c int resume(struct device *device, int pm_policy); -PMA would call this when it is doing resume operations on devices. The device -driver would do the necessary resume operation on its device based on the -policy specified by the PMA in the argument. +The PMA calls this function to resume operations on the devices on which it +had previously performed suspend operations. The device driver performs the +necessary resume operations on its device, following the power management +policy specified in the function's argument. -It would return 0 if successful. In all other cases it would return an -appropriate negative :c:macro:`errno` value. +The function returns 0 if successful. In all other cases it returns an +appropriate negative :code:`errno` value. -Device Model with Power Management support +Device Model with Power Management Support ========================================== -Drivers that have Power Management support should initialize their devices -using the folllowing macros that are designed to take additional parameters -necessary to initialize the power management related handlers implemented by -the drivers. Following are the macros: -:c:macro:`DEVICE_AND_API_INIT_PM` +Drivers initialize the devices using macros. See :ref:`device_drivers` for +details on how these macros are used. Extended versions of the macros are +provided for drivers with power management support. The macros take +additional parameters that are necessary to initialize pointers to the power +management related handler functions. - This should be used where :c:macro:`DEVICE_AND_API_INIT` macro would be - used +These macros should be used: -:c:macro:`DEVICE_INIT_PM` +:code:`DEVICE_AND_API_INIT_PM` - This should be used where :c:macro:`DEVICE_INIT` macro would be used + Use this macro in place of the :code:`DEVICE_AND_API_INIT` macro. -:c:macro:`SYS_INIT_PM` +:code:`DEVICE_INIT_PM` - This should be used where :c:macro:`SYS_INIT` macro would be used + Use this macro in place of the :code:`DEVICE_INIT` macro. -Device PM API for PMA -===================== -These APIs will be used by the PMA to do suspend and resume operations on the +:code:`SYS_INIT_PM` + + Use this macro in place of the :code:`SYS_INIT` macro. + +Device Power Management API for the PMA +======================================= + +The PMA uses these APIs to perform suspend and resume operations on the devices. -Getting the Device List ------------------------ +Get Device List +--------------- + .. code-block:: c void device_list_get(struct device **device_list, int *device_count); -This api is used by the PMA to get the device list that the Zephyr kernel -internally maintains for all devices in the system. The device structure in -the list will be used to identify devices that the PMA would chose to do PM -operations on. +The Zephyr kernel internally maintains a list of all devices in the system. +The PMA uses this API to get the device list. The PMA can use the list to +identify the devices on which to execute power management operations. -The PMA can use this list to create its own sorted order list based on device -dependencies. It can also create device groups to execute different policies +The PMA can use this list to create a sorted order list based on device +dependencies. The PMA creates device groups to execute different policies on each device group. .. note:: - PMA should take care that it does not alter the original list, since that is - the list the kernel uses. + + Ensure that the PMA does not alter the original list. Since the kernel + uses the original list, it should remain unchanged. PMA Device Suspend API ---------------------- + .. code-block:: c int device_suspend(struct device *device, int pm_policy); -This function would call the :c:func:`suspend()` handler function implemented -by the device driver for the device. Refer to -`Device Suspend Operation Handler function`_ for more information. +Calls the :c:func:`suspend()` handler function implemented by the device +driver. See :ref:`dev_suspend_handler` for more information. PMA Device Resume API --------------------- + .. code-block:: c int device_resume(struct device *device, int pm_policy); -This function would call the :c:func:`resume()` handler function implemented by -the device driver for the device. Refer to -`Device Resume Operation Handler function`_ for more information. +Calls the :c:func:`resume()` handler function implemented by the device +driver. See :ref:`dev_resume_handler` for more information. -Device Busy Status Indication -============================= -Some power policies executed by the PMA could turn off power to devices causing -them to lose state. If such devices are in the middle of some hardware -transaction (e.g. write to flash memory), when the power is turned off, then -such transactions would be left in an inconsistent state. This infrastructure -is to enable devices guard such transactions by indicating to the PMA that it -is in the middle of a hardware transaction. +Busy Status Indication +====================== -During a call to :c:func:`_sys_soc_suspend()`, if PMA finds any device is busy, -then it may decide to choose a policy other than Deep Sleep or defer PM -operations till the next call to :c:func:`_sys_soc_suspend()`. +The PMA executes some power policies that can turn off power to devices, +causing them to lose their state. If the devices are in the middle of some +hardware transaction, like writing to flash memory when the power is turned +off, then such transactions would be left in an inconsistent state. This +infrastructure guards such transactions by indicating to the PMA that +the device is in the middle of a hardware transaction. -.. note:: - It is up to the device driver writer to decide whether a transaction needs - to be guarded using these APIs. If there are other recovery or retrial - methods in place, then the driver could choose to avoid guarding the - transactions. +When the :code:`_sys_soc_suspend()` is called, the PMA checks if any device +is busy. The PMA can then decide to execute a policy other than deep sleep or +to defer power management operations until the next call of +:code:`_sys_soc_suspend()`. + +If other recovery or retrieval methods are in place, the driver can avoid +guarding the transactions. Not all hardware transactions must be guarded. The +Zephyr kernel provides the following APIs for the device drivers and the PMA +to decide whether a particular transaction must be guarded. + +Indicate Busy Status API +------------------------ -Device API to Indicate Busy Status ----------------------------------- .. code-block:: c void device_busy_set(struct device *busy_dev); -This API will set a bit corresponding to the device, in a data structure -maintained by the kernel, to indicate it is in the middle of a transaction. +Sets a bit corresponding to the device, in a data structure maintained by the +kernel, to indicate whether or not it is in the middle of a transaction. + +Clear Busy Status API +--------------------- -Device API to Clear Busy Status -------------------------------- .. code-block:: c void device_busy_clear(struct device *busy_dev); -This API will clear a bit corresponding to the device, in a data structure -maintained by the kernel, to indicate it is not in the middle of a transaction. +Clears the bit corresponding to the device in a data structure +maintained by the kernel to indicate that the device is not in the middle of +a transaction. + +Check Busy Status of Single Device API +-------------------------------------- -PMA API to Check Busy Status of Single Device ---------------------------------------------- .. code-block:: c int device_busy_check(struct device *chk_dev); -This API is called by the PMA for each device to check its busy status. It -returns 0 if the device is not busy. +Checks whether a device is busy. The API returns 0 if the device +is not busy. + +Check Busy Status of All Devices API +------------------------------------ -PMA API to Check Busy Status of All Devices -------------------------------------------- .. code-block:: c int device_any_busy_check(void); -This API is called by the PMA to check if any device is busy. It returns 0 if -no device in the system is busy. +Checks if any device is busy. The API returns 0 if no device in the system is busy. + +.. _pm_config_flags: + +Power Management Configuration Flags +************************************ -Power Management Config Flags -***************************** The Power Management features can be individually enabled and disabled using -the following config flags. +the following configuration flags. -`CONFIG_SYS_POWER_MANAGEMENT` - This enables the Power Management Subsystem. +:code:`CONFIG_SYS_POWER_MANAGEMENT` -`CONFIG_SYS_POWER_LOW_POWER_STATE` - PMA should enable this flag if it would use `SYS_PM_LOW_POWER_STATE` - policy. + This flag enables the power management subsystem. -`CONFIG_SYS_POWER_DEEP_SLEEP` - This flag would enable support for the `SYS_PM_DEEP_SLEEP` policy. +:code:`CONFIG_SYS_POWER_LOW_POWER_STATE` -`CONFIG_DEVICE_POWER_MANAGEMENT` - This flag should be enabled if device power management is supported by - the PMA and the devices. + The PMA enables this flag to use the :code:`SYS_PM_LOW_POWER_STATE` policy. + +:code:`CONFIG_SYS_POWER_DEEP_SLEEP` + + This flag enables support for the :code:`SYS_PM_DEEP_SLEEP` policy. + +:code:`CONFIG_DEVICE_POWER_MANAGEMENT` + + This flag is enabled if the PMA and the devices support device power + management. Writing a Power Management Application ************************************** -This section describes the steps involved in writing a typical Power Management -Application to enforce policies using the Power Management APIs. This -demonstrates the various scenarios that the PMA would consider in the policy -decision process. -.. note:: +A typical PMA executes policies through power management APIS. This section +details various scenarios that can be used to help developers write their own +custom PMAs. - The Power Management Application would be part of a larger application - that does more than just power management. Here we refer to the Power - Management part of the application. +The PMA is part of a larger application doing more than just power +management. This section focuses on the power management aspects of the +application. Initial Setup ============= -To enable Power Management support, the application would do the following: -- Enable CONFIG_SYS_POWER_MANAGEMENT flag +To enable the power management support, the application must do the following: -- Enable other required config flags described in - `Power Management Config Flags`_. +#. Enable the :code:`CONFIG_SYS_POWER_MANAGEMENT` flag -- Implement the hook functions described in - `Power Management Hook Infrastructure`_. +#. Enable other required config flags described in :ref:`pm_config_flags`. -Get Device List and Create Policies -=================================== -The first act of the PMA will be to retrieve the known list of devices through -the :c:func:`device_list_get()` function. Because the PMA is part of the -application, it is expected to start after all devices in the system have been -initialized. Thus the list of devices is not expected to change once the -application has begun. +#. Implement the hook functions described in :ref:`pm_hook_infra`. -The :c:func:`device_list_get()` function will return an array of current -enabled devices. It is up to the PMA to walk this list and determine the best -mechanism to store/process this list. It is up to the system integrator to -verify the amount of time each device requires for a power cycle, and ensure -this time fits within the allotted time provided by the kernel. This time -value is highly dependent upon each specific device used in the final platform -and SOC. +Device List and Policies +======================== + +The PMA retrieves the list of enabled devices in the system using the +:c:func:`device_list_get()` function. Since the PMA is part of the +application, the PMA starts after all devices in the system have been +initialized. Thus, the list of devices will not change once the application +has begun. Once the device list has been retrieved and stored, the PMA can form device -groups and sorted lists based on device dependencies. Using the device lists -and the known aggregate wake latency of the combination of power operations, -the PMA would then create fine grain custom power policies. Finally it would -map these custom policies to the policy categories defined by the Power -Management subsystem as described in `Policies`_. +groups and sorted lists based on device dependencies. The PMA uses the device +lists and the known aggregate wake latency of the combination of power +operations to create the fine grain custom power policies. Finally, the PMA +maps these custom policies to the policy categories defined by the power +management subsystem as described in `Policies`_. Scenarios During Suspend ======================== -When the :c:func:`_sys_soc_suspend()` function is called by the Power -Management subsystem, the PMA can select between multiple scenarios. -**Case 1:** +When the power management subsystem calls the :code:`_sys_soc_suspend()` +function, the PMA can select between multiple scenarios. -The time allotted is too short for any power management. In this case, the PMA -will leave interrupts disabled, and return the code SYS_PM_NOT_HANDLED. This -will allow the Zephyr kernel to continue with its normal idling process. +Scenario 1 +---------- -**Case 2:** +The time allotted is too short for any power management. -The time allotted is enough for some devices to be suspended. +In this case, the PMA leaves the interrupts disabled, and returns the code +:code:`SYS_PM_NOT_HANDLED`. This actions allow the Zephyr kernel to continue +with its normal idling process. -.. code-block:: none +Scenario 2 +---------- - Scan through the devices that meet the criteria +The time allotted allows the suspension of some devices. - Call device_suspend() for each device +The PMA scans through the devices that meet the criteria and calls the +:c:func:`device_suspend()` function for each device. - If everything suspends correctly, the PMA will: +After all devices are suspended properly, the PMA executes the following +operations: - If the time allotted is enough for SYS_PM_LOW_POWER_STATE policy +* If the time allotted is enough for the :code:`SYS_PM_LOW_POWER_STATE` + policy: - Setup wake event Push the CPU to LPS re-enabling interrupts at the - same time. + #. The PMA sets up the wake event, puts the CPU in a LPS, and re- enables + the interrupts at the same time. - Return SYS_PM_LOW_POWER_STATE + #. The PMA returns the :code:`SYS_PM_LOW_POWER_STATE` code. - If the time allotted is not enough for SYS_PM_LOW_POWER_STATE +* If the time allotted is not enough for the :code:`SYS_PM_LOW_POWER_STATE` +policy, the PMA returns the :code:`SYS_PM_DEVICE_SUSPEND_ONLY` code. - Return SYS_PM_DEVICE_SUSPEND_ONLY +When a device fails to suspend, the PMA executes the following operations: - If a device fails to suspend, the PMA will: +* If the system integrator determined that the device is not essential to the + suspend process, the PMA can ignore the failure. - If the device is not essential to the suspend process, as determined by - the system integrator, the PMA can choose to ignore the failure. +* If the system integrator determined that the device is essential to the + suspend process, the PMA takes any necessary recovery actions and + returns the :code:`SYS_PM_NOT_HANDLED` code. - If the device is essential to the suspend process, as determined by the - system integrator, the PMA shall take any necessary recovery actions and - return SYS_PM_NOT_HANDLED. - -**Case 3:** +Scenario 3 +---------- The time allotted is enough for all devices to be suspended. -.. code-block:: none +The PMA calls the :c:func:`device_suspend()` function for each device. - Call device_suspend() for each device. +After all devices are suspended properly and the time allotted is enough for +the :code:`SYS_PM_DEEP_SLEEP` policy, the PMA executes the following +operations: - If everything suspends correctly, the PMA will: +#. Calls the :c:func:`device_any_busy_check()` function to get device busy + status. If any device is busy, the PMA must choose a policy other than + :code:`SYS_PM_DEEP_SLEEP`. +#. Sets up wake event. +#. Puts the SOC in the deep sleep state. +#. Re-enables interrupts. +#. Returns the :code:`SYS_PM_DEEP_SLEEP` code. - If the time allotted is enough for SYS_PM_DEEP_SLEEP policy +If, on the other hand, the time allotted is only enough for the +:code:`SYS_PM_LOW_POWER_STATE` policy, The PMA executes the following +operations: - Call device_any_busy_check() to get device busy status +#. Sets up wake event. +#. Puts the CPU in a LPS re-enabling interrupts at the same time. +#. Returns the :code:`SYS_PM_LOW_POWER_STATE` code. - If any device is busy +If the time allotted is not enough for any CPU or SOC power management +operations, the PMA returns the :code:`SYS_PM_DEVICE_SUSPEND_ONLY` code. - Choose policy other than SYS_PM_DEEP_SLEEP +When a device fails to suspend, the PMA executes the following operations: - Setup wake event +* If the system integrator determined that the device is not essential to the + suspend process the PMA can ignore the failure. - Push the SOC to Deep Sleep - - Re-enable interrupts - - Return SYS_PM_DEEP_SLEEP - - If the time allotted is enough for SYS_PM_LOW_POWER_STATE policy - - Setup wake event - - Push the CPU to LPS re-enabling interrupts at the same time. - - Return SYS_PM_LOW_POWER_STATE - - If the time allotted is not enough for any CPU or SOC operations - - Return SYS_PM_DEVICE_SUSPEND_ONLY - - If a device fails to suspend, the PMA will: - - If the device is not essential to the suspend process, as determined by - the system integrator, the PMA can choose to ignore the failure. - - If the device is essential to the suspend process, as determined by the - system integrator, the PMA shall take any necessary recovery actions and - return SYS_PM_NOT_HANDLED. +* If the system integrator determined that the device is essential to the + suspend process, the PMA takes any necessary recovery actions and + returns the :code:`SYS_PM_NOT_HANDLED` code. Policy Decision Summary ======================= - +------------------------------+---------------------------+ - | PM operations | Policy and Return Code | - +==============================+===========================+ - | Suspend some devices & | SYS_PM_LOW_POWER_STATE | - | | | - | Enter Low Power State | | - +------------------------------+---------------------------+ - | Suspend all devices & | SYS_PM_LOW_POWER_STATE | - | | | - | Enter Low Power State | | - +------------------------------+---------------------------+ - | Suspend all devices & | SYS_PM_DEEP_SLEEP | - | | | - | Enter Deep Sleep | | - +------------------------------+---------------------------+ - | Suspend some or all devices &| SYS_PM_DEVICE_SUSPEND_ONLY| - | | | - | No CPU/SoC PM Operation | | - +------------------------------+---------------------------+ - | No PM operation | SYS_PM_NOT_HANDLED | - +------------------------------+---------------------------+ ++---------------------------------+---------------------------------------+ +| PM operations | Policy and Return Code | ++=================================+=======================================+ +| Suspend some devices and | :code:`SYS_PM_LOW_POWER_STATE` | +| | | +| Enter Low Power State | | ++---------------------------------+---------------------------------------+ +| Suspend all devices and | :code:`SYS_PM_LOW_POWER_STATE` | +| | | +| Enter Low Power State | | ++---------------------------------+---------------------------------------+ +| Suspend all devices and | :code:`SYS_PM_DEEP_SLEEP` | +| | | +| Enter Deep Sleep | | ++---------------------------------+---------------------------------------+ +| Suspend some or all devices and | :code:`SYS_PM_DEVICE_SUSPEND_ONLY` | +| | | +| No CPU/SoC PM Operation | | ++---------------------------------+---------------------------------------+ +| No PM operation | :code:`SYS_PM_NOT_HANDLED` | ++---------------------------------+---------------------------------------+