RFC [1/3] - SoC, CPU LPS, Tickless idle and Device power management

Thomas, Ramesh

***This part is merged***

Kernel SOC power management hook infrastructure in Zephyr
This infrastructure provides hooks at locations where the kernel goes to
idle to enable the PM service application to do suspend operations
around them.

This infrastructure can be used by power manager app to implement PM
policy and to put system to various power states. A sample PM
application is provided as an example to demonstrate how to use these
hooks and the states it uses (listed below) are for demonstration
purpose. It is up to the implementer of the PM service app to design their own.

1. LPS:
CPU is put in low power states like C2. The CPU states are not lost.
Woken up by any interrupt.

2. Deep Sleep:
The SoC is put in deep sleep state saving most power. In this state, CPU
power is off while SRAM contents are retained. Woken up by deep
sleep wake up events of SoC. On wake up, execution will resume from
reset vector.

3. Tickless Idle power saving:
Zephyr kernel has its own idling called Tickless idle. PM service can
take advantage of this by turning off peripherals to save more power
when the hook infrastructure notifies it before going to idle. It will
be notified again when kernel exits the tickless idle state when it can
restore states it altered.

The hook functions:
These functions must be implemented by the power management service app.

a) int _sys_soc_suspend(int32_t ticks)
param ticks:
- the upcoming kernel idle time

- non-zero value if it uses its own idle or deep sleep. If a zero value
is returned, then kernel will enter its own idle.

This is called immediately before the kernel prepares to go into its
idle state. The PM service, based on the amount of idle time available,
chooses an appropriate power policy comparing the wake latencies involved.

For CPU low power states it would put the CPU in states like C2. For
SoC deep sleep states, it would do the required SoC specific operation.
In these, it would return a non-zero value indicating it has fully
handled the idle and the kernel will not enter its own idle.

For tickless idle power saving, the PM service app can turn off as many
peripherals it requires and then returns a zero value. The zero return
value would indicate to the kernel that it should do its own idle.

This function is entered with interrupts disabled. It should re-enable
interrupts if it does its own idle or deep sleep. If it returns zero
then it should not enable interrupts so the kernel can go to idle state
without interruption.

b) void _sys_soc_resume(void)

The main purpose of this hook is to notify PM service of exit from SoC
deep sleep state, CPU low power and tickless idle exit. Any states
altered at _sys_soc_suspend() should be restored in this function.

This hook function is called from 2 different locations in the kernel.
PM service will check its internal states to determine which state the
system recovering from.

Following are the 2 different locations where it called from:
1. At kernel start recovering from deep sleep or entering cold boot.
Deep sleep causes all CPU states to be lost so the system resumes at the
reset vector taking the same path as cold boot. Since kernel does not
save any state to identify whether it is recovering from cold boot or
deep sleep, it would call this function in both cases. PM service can
use SoC specific sticky registers that can retain values across deep
sleep to identify whether it is resuming from deep sleep. In the case
of cold boot, these registers would get reset.

If it is cold boot then this function should return immediately doing

If it is recovering from deep sleep then it should restore states
including CPU registers and stack stored in _sys_soc_suspend().
Execution context should then switch to execution inside
_sys_soc_suspend() at the location where it put the system to deep sleep.

In this location, this function is called using a temporary stack that
is also used by interrupts. It is important that this function switches
to the stack that was saved during _sys_soc_suspend before interrupts
are enabled when returning from _sys_soc_suspend() to avoid interfering
with interrupt handlers use of this stack.

2. After the exit of tickless idle or a low power CPU state from the
context of the ISR that caused the exit. In this case, PM service will
restore altered states and return.