Workaround for Suspend using core idle or ring Oscillator Mode in PXA320
Power Management is one of the crucial aspects of the handheld design. In various handhelds, the power management states and transition to these states without losing the operating context is the key to effective implementation of Power Management. The design decision of device power states, individual module power states in each of the power states, trigger sources configuration for each state etc are very important steps in the design stage. The design stage also involves the incorporation of the device power stages in to Windows CE Power Management framework.
This blog describes one interesting problem encountered in PXA320 CPU power modes in a Windows CE based design.
We all know that, OEMPowerOFF () is responsible for final power down state in Windows Embedded CE 6.0. This function is called by Windows CE 6.0 when the OFF button is pressed or The GWES times out in its power-down timer. When this function is called, the OEM’s normally place the device in lowest power state and place the CPU in standby mode. Normally suspend is implemented using standby mode of the process power state. Unfortunately standby mode is not supported by PXA320, unlike PXA270 which supports Standby mode. Also, Sleep mode is not preferable as it will require CPU restart, meaning the context will be lost, as good as reboot.
The next preferable states are core idle and ring oscillator mode. Let us discuss one by one. In core idle, the processor core is entered in to the idle state, the program counter value is retained and the CPU core stalls execution. All other internal peripherals will be on. Processor will be woken up by any unmasked interrupt and the core resumes execution from there. All clocks are active during the core idle state, except the core clock.
Now here is the catch. OS Timers are used by the kernel to run the scheduler. OS Timer interrupt is used to run the scheduler. If the rescheduling time matches the OS timer count register (OSCR) then interrupt will be generated. Next rescheduling time (dwReschedTime) is written to the OS Timer match register (OSMR0) by the timer interrupt handler or OALTimerUpdateRescheduleTime () based on conditions. dwReschedTime is a global variable in NK.exe maintaining the next rescheduling time.
In core idle mode, all the interrupts is masked (including the OS timer Interrupts) excluding the wake up sources. But OSMR0 and OSCR are being updated in the core idle state. When OSMR matches with OSCR, it reaches the rescheduling time and the scheduler has to be called. But the scheduler will not be called, as the OS timer interrupt is masked to ensure the suspend state of the core. Further interrupts from the OS timer for invoking the scheduler will not happen, as the OSMR0 is not updated.
Due to this reason, the scheduler will fail to run during the wakeup and the system will hang just after wake up. In this case the system will respond only for the interrupt because ISR and IST will be executed. In ARM architecture Interrupt handling is done through the exception.
In ring oscillator mode, the core will not stop. Interrupt mask and wake up will be emulated through the software. During the wake up same behavior will occur as explained above for core idle state.
- Backup the OSCR and OSMR0 value in temporary variables before entering in to the core idle state or ring oscillator mode in OEMPowerOFF ().
- Restore the OSCR and OSMR0 value from the temporary variables upon wake up.
This workaround resolve the timing miss match between the OS Timer registers and the dwReschedTime and make a successful wake up from the suspend.