Symbian3/PDK/Source/GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Fri, 16 Jul 2010 17:23:46 +0100
changeset 12 80ef3a206772
parent 9 59758314f811
child 14 578be2adaf3e
permissions -rw-r--r--
Week 28 contribution of PDK documentation content. See release notes for details. Fixes bugs Bug 1897, Bug 344, Bug 2681, Bug 463, Bug 1522.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept id="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703" xml:lang="en"><title>Power
Controller DPowerController Implementation Tutorial</title><shortdesc>This topic describes how to implement the <codeph>DPowerController</codeph> class
to provide the main power controller functionality in a base port.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody>
<p><xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> is defined as: </p>
<codeblock id="GUID-95318C39-B205-557C-B1F3-75C1441E464A" xml:space="preserve">class DPowerController : public DBase
    {
public:
    IMPORT_C DPowerController();
    IMPORT_C void Register();
    IMPORT_C void WakeupEvent();

#ifndef __X86__
    IMPORT_C TInt RegisterResourceController(DBase* aController, TInt aClientId);
private:
    struct SResourceControllerData
        {
        DBase* iResourceController;
        TInt   iClientId;
        } iResourceControllerData;
#endif

public:
    volatile TPowerState    iTargetState;
public:
    virtual void CpuIdle() = 0;
    virtual void EnableWakeupEvents() = 0;
    virtual void DisableWakeupEvents() = 0;
    virtual void AbsoluteTimerExpired() = 0;
    virtual void PowerDown(TTimeK aWakeupTime) = 0;
    };
      </codeblock>
<p>The first three functions are exported from the kernel, <filepath>EKERN.EXE</filepath>,
while the other five pure virtual functions are implemented by your base port.
You do not need to export any other functions. </p>
<ul>
<li id="GUID-2EEFEFF3-FCAF-526C-A11B-790A2A47AA9C"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-BCCDBA09-415D-5779-BCE5-CDEB2E1EF7D8">Initialising the power controller</xref>, </p> </li>
<li id="GUID-CBB1EE9C-CD27-5417-973C-3BBED74715D6"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-DCD91EBA-CB0E-5EA9-84E0-8F8FED6FC91E">DPowerController::RegisterResourceController()</xref>, </p> </li>
<li id="GUID-4E2D396D-E6FA-5658-830F-9F82D4A63AD1"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-5A0CAD08-AA12-56EE-B0A3-75548D1896C9">DPowerController::EnableWakeupEvents()</xref>, </p> </li>
<li id="GUID-DB82BCE3-702A-51EB-ADE0-9434D59CD553"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-51D37A0C-AD46-52D5-A31C-CB3A8046CE84">DPowerController::AbsoluteTimerExpired()</xref>, </p> </li>
<li id="GUID-77CCBFFE-037D-5B86-BF14-1BE87D38B47A"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-1F77C71C-D226-58BB-ABAE-43F958CC0C61">DPowerController::PowerDown()</xref>, </p> </li>
<li id="GUID-8657D772-2338-588D-B074-832B06144D8B"><p> <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-E2A072D0-A67F-5E6D-81ED-CFD77B6ED4F1">CpuIdle()</xref>. </p> </li>
</ul>
<section id="GUID-BCCDBA09-415D-5779-BCE5-CDEB2E1EF7D8"><title>Initialising
the power controller</title> <p>Typically, you implement your derived class
in a power management kernel extension, which has the opportunity to perform
initialisation before the system itself is fully initialised. This is done
via the extension's DLL entry point. You use the <xref href="GUID-7964FC46-4641-3BDD-92C9-50FA22C3321A.dita"><apiname>DECLARE_STANDARD_EXTENSION()</apiname></xref> macro
as a wrapper around your initialisation code. There are at least three things
to do here: </p> <ul>
<li id="GUID-25C66F1B-6B2F-5B3B-A827-410263EE22A4"><p>create an instance of
your power controller object </p> </li>
<li id="GUID-369A09EC-74D3-529A-AC05-0EFE0C4ABBF7"><p>register your power
controller object with the Symbian platform power manager, by calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-F66D72D0-AA27-3BAF-8915-C6E8CC4E7CCF"><apiname>DPowerController::Register()</apiname></xref>.
Your power controller cannot be used by the Symbian platform power manager
until it has been registered. </p> </li>
<li id="GUID-E4C7D934-AAB9-511B-93A4-125D5A5B248D"><p>if you intend to use
a battery monitor, then you would create it and register it as the HAL handler
to deal with <xref href="GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7.dita#GUID-66A851A0-2A0C-3624-AEC1-22F6629FABF7/GUID-227B4DCD-5D74-3AB7-8E09-64A04D88F094"><apiname>THalFunctionGroup::EHALGroupPower</apiname></xref> calls. See <xref href="GUID-65CDCA83-C726-5173-8E46-B8981D1D7B02.dita">Battery Monitor Implementation
Tutorialc</xref> and <xref href="GUID-54042C84-6216-5930-9CBF-BAF635CECD4D.dita">Power
HAL Handler Tutorial</xref> for more detail. </p> </li>
</ul> <p>For example: </p> <codeblock id="GUID-1A909C4C-DCAF-54E3-B482-16918E33BF4F" xml:space="preserve">DECLARE_STANDARD_EXTENSION()
    {
    TInt r=KErrNoMemory;

    // Create the power controller object, and register it.
    DPowerController* pC = new DYourPowerController;
    if !(pC)
        {
        return (r);
        }
        pC-&gt;Register();

    // Create the battery monitor.
    DBatteryMonitor* pM = new DYourBatteryMonitor;
    if !(pM)
        {
        return(r);
        }

    r = KErrNone;
    return(r);
    }</codeblock> </section>
<section id="GUID-DCD91EBA-CB0E-5EA9-84E0-8F8FED6FC91E"><title>DPowerController::RegisterResourceController()</title> <p>The
function <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-42896B4D-9F77-3D91-82BD-50102A8F3DA4"><apiname>DPowerController::RegisterResourceController()</apiname></xref> allows
the Resource Controller to register itself with the Power Controller. See <xref href="GUID-66FD040B-133E-57CF-80DD-9369F62709C6.dita#GUID-66FD040B-133E-57CF-80DD-9369F62709C6/GUID-08BFCAF4-9AF0-5999-A1C4-7BBD107C9354">registering
with the resource controller</xref> in the PSL implementation document. </p> <p>To
support idle power management the Power Controller's PSL must override <codeph>RegisterResourceController()</codeph> to
include the registration of a list of resources whose states are of interest
to idle power management. </p> <p><b>Idle
power management</b> </p> <p>The Power Controller can assemble a list of resources
whose state it is interested in from a NULL thread in an array of <xref href="GUID-586AF75A-8350-345D-ABF4-6542C8E75DED.dita"><apiname>SIdleResourceInfo</apiname></xref> structures.
Each entry in the list contains the resource ID that the power controller
must enter before registering with the PRM. The resource list should be created
in the kernel heap or data section. </p> <p>The example below creates a buffer
to capture the state of all static resources. The PRM captures the information
using <xref href="GUID-46F2174F-0206-345B-8C5D-F8B5763652E0.dita#GUID-46F2174F-0206-345B-8C5D-F8B5763652E0/GUID-52DC308A-9DF1-3BDE-A905-A4DD3B692638"><apiname>DPowerResourceController::RegisterResourcesForIdle()</apiname></xref>. </p> <codeblock id="GUID-C6E907FD-094D-5412-8F81-FC02CDE8B411" xml:space="preserve">    ...
//Allocate buffer for Idle resource management
    NKern::ThreadEnterCS();
    pBuf = HBuf::New(numResources * sizeof(SIdleResourceInfo)); 
    NKern::ThreadLeaveCS();
    if(!pBuf)
        {
           return KErrNoMemory;
        }
    SIdleResourceInfo* pI = (SIdleResourceInfo*)pBuf-&gt;Ptr();

//Update resource ID
    for(TUint c = 0; c &lt; numResources; c++)
        {
        pI[c].iResourceId = c+1; 
        }
    r = (iResourceControllerData.iResourceController)-&gt;RegisterResourcesForIdle(iResourceControllerData.iClientId, numResources, (TPtr*)pI);
    ...</codeblock> <p>The first parameter passed to <codeph>RegisterResourcesForIdle()</codeph> is
the client Id generated for the power controller this is the client ID passed
by the PRM when calling <xref href="GUID-B2C466D1-0B65-3BB7-81B1-7297400E60C4.dita"><apiname>RegisterResourceController</apiname></xref>. </p> <p> <b>Note</b>: <codeph>RegisterResourcesForIdle()</codeph> is
not exported and is only available for use by the Power Controller to register
resources for idle power management. <b>Note</b>: <codeph>RegisterResourcesForIdle()</codeph> can
only be called by the Power Controller once. </p> </section>
<section id="GUID-5A0CAD08-AA12-56EE-B0A3-75548D1896C9"><title>DPowerController::EnableWakeupEvents()</title> <codeblock id="GUID-38714507-C38C-5787-997F-5D45F3A90357" xml:space="preserve">virtual void EnableWakeupEvents() = 0;</codeblock> <p>The
Symbian Power Model defines 3 generic system-wide <xref href="GUID-113B3755-1797-5D1B-8E07-8A18F5FE1504.dita">power
states</xref>: <i>Active</i>, <i>Standby</i> and <i>Off</i>, as defined in
the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita">Symbian platform
power model</xref>. </p> <p>Each of the system-wide low power states: <i>Standby</i> and <i>Off</i>,
has a defined set of wake-up events. If a wake-up event occurs while the system
is preparing to transition into one of these low power states, or when the
system is in the <i>Standby</i> state, then this can result in the system
moving back to the <i>Active</i> power state. Wake-up events may be different
for different target power states. Wake-up events are platform-specific hardware
events, and it is your base port that decides which events count as wake-up
events. </p> <p><b>When
is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-0642129D-05F2-3AB0-B562-37A7BB7A275F"><apiname>DPowerController::EnableWakeupEvents()</apiname></xref> is
called called by the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power
manager</xref> as a result of a user side call to <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-C49C0A07-EAC7-32CB-956F-1FFEFF2FD326"><apiname>Power::EnableWakeupEvents()</apiname></xref>.
The class <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita"><apiname>Power</apiname></xref> is the user side interface to the power
manager, and is used by the user side entity that is responsible for moving
the device into a low power state. </p> <p><b>Context</b> </p> <p>When the user side entity decides to move the device to a low power
state, it sends a notification to all of the user side power domains registered
with it, giving their applications a chance to save their data and state.
However, before doing this, it calls <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-C49C0A07-EAC7-32CB-956F-1FFEFF2FD326"><apiname>Power::EnableWakeupEvents()</apiname></xref>.
It also calls <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-6CFE19D9-249A-3305-8224-823D2FDB1859"><apiname>Power::RequestWakeupEventNotification()</apiname></xref> so
that it can be informed of a wake-up event. If it is notified of a wake-up
event, it can halt, and reverse the user side response to the power transition. </p> <fig id="GUID-ACC6E7E3-71E3-5553-B433-9017CB04513D">
<image href="GUID-65F3E8BD-22C9-5CF2-A3CC-270C24ADECC0_d0e394112_href.png" placement="inline"/>
</fig> <p>Before calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-0642129D-05F2-3AB0-B562-37A7BB7A275F"><apiname>DPowerController::EnableWakeupEvents()</apiname></xref>,
the power manager sets the <codeph>iTargetState</codeph> member of <codeph>DPowerController</codeph> to
the applicable <xref href="GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0.dita"><apiname>TPowerState</apiname></xref>. This means that you can enable
the appropriate set of wake-up events. </p> <p>Once the user side transition
is complete, it calls <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-7C6F3F0F-319B-3DEE-81BF-1EB5BB2EAB0A"><apiname>Power::PowerDown()</apiname></xref> in the user side
interface to the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power
manager</xref>, which results in a call to <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> in
the power controller. This starts the transition of all <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-DC5F1ECD-CCA3-59FF-A2F1-A3DBD76CD458">power handlers</xref> to a low power state, a potentially long process. This
means that the power controller needs the ability to detect wake-up events
so that it can halt, and reverse the power transition. </p> <p><b>Implementation issues</b> </p> <p>There are three possibilities in dealing
with wake-up events: </p> <ul>
<li id="GUID-4243E6DD-C903-58DE-B125-38CEDB8B5269"><p>if wake-up events are
not handled by specific peripheral drivers, you could set up the hardware
so that wake-up events are recorded in a location accessible by the software.
Prior to completing the system power transition, the Power controller would
check the relevant hardware to see whether a wakeup event had occurred. On
detecting a wake-up event it would tell the power manager by calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C193F898-2C15-3C42-8353-14F00789BCDA"><apiname>DPowerController::WakeupEvent()</apiname></xref>. </p> </li>
<li id="GUID-289B86C4-A578-5A42-A0DF-70A7BF3F440E"><p>if wake-up events are
not handled by specific peripheral drivers, you could arrange for wake-up
events to interrupt the CPU. The code that services those interrupts would
tell the power manager by calling <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-FABDB7E2-DEC5-3EA9-8106-66C971C04AB7"><apiname>DPowerController::WakepEvent()</apiname></xref>. </p> </li>
<li id="GUID-E51BAE55-0A81-5D1F-B509-096A7F2141EF"><p>if wakeup events are
intercepted, serviced and cleared by peripheral drivers, then the following
outline solution could be adopted: </p> <ul>
<li id="GUID-5C942237-BBB2-5919-8578-B55BDAFAFC9F"><p>The power controller
would need to publish a list of wake-up events, preferably as a bit mask,
and export an API which peripheral drivers could use to notify the power controller
that a wake-up event has occurred. The following interface class could be
used for this purpose: </p> <codeblock id="GUID-084F7F46-66B6-5661-85AF-57D499250886" xml:space="preserve">class TPowerController
    {
public:
    inline static void SetPowerControllerPointer(DPowerController* apPowerController)
    { iPowerControllerPointer = apPowerController; }
    IMPORT_C static void WakeupEventOccurred(TUint aWakeupEvent);
    …        // other methods if required
private:
    DPowerController* iPowerControllerPointer;
    };
                      </codeblock> <p>The class would be implemented as part
of the power management kernel extension and <codeph>SetPowerControllerPointer()</codeph> would
be called when <xref href="GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703.dita#GUID-34D1D0BF-20DE-5677-A067-8FF9DD72E703/GUID-BCCDBA09-415D-5779-BCE5-CDEB2E1EF7D8">initialising
the power controller</xref>, but after creation of the power controller object. </p> <p>Those
peripheral drivers that intercept wake-up events would need to link to the
power controller DLL (i.e. the power management kernel extension). </p> <p>On
the occurrence of a wake-up event, the peripheral driver software servicing
that event would notify the power controller by calling <codeph>WakeupEventOccurred()</codeph>,
specifying the appropriate wake-up event bit(s). </p> <p>You might implement <codeph>WakeupEventOccurred()</codeph> as
follows: </p> <codeblock id="GUID-501ABA28-81B9-52C1-9842-003E1E389045" xml:space="preserve">EXPORT_C void TPowerController::WakeupEventOccurred(TUint aWakeupEvent)
    {
    if(iPowerControllerPointer-&gt;iWakeupEvents &amp; aWakeupEvent)
        {
        iPowerControllerPointer-&gt;WakeupEvent();
        }
    }</codeblock> <p>where <codeph>iWakeupEvents</codeph> is a data member
defined in your <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> -derived class that contains
the bitmask representing the wake-up events. The bitmask groups wakeup events
according to the target power state. </p> </li>
</ul> </li>
</ul> <p>When the peripheral driver powers down, it should leave the hardware
that generates the wake-up event powered and enabled for detection. Thus,
if a wake-up event of the type handled by this peripheral driver occurs, it
will not be serviced in the normal way, but will be left pending until the
power controller services it. </p> <p>When the power controller’s <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> function
is called, the power controller must check the peripheral hardware directly
to see whether the wakeup event has happened, or is happening right now, prior
to transitioning the device to the target system-wide low power state. If
the wake-up event is found to have happened then <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> would
return immediately, instead of initiating the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-DC5F1ECD-CCA3-59FF-A2F1-A3DBD76CD458">power
handlers</xref> power down of the peripheral drivers. </p> </section>
<section id="GUID-51D37A0C-AD46-52D5-A31C-CB3A8046CE84"><title> DPowerController::AbsoluteTimerExpired()</title> <codeblock id="GUID-5EC61B73-DA37-51C8-963F-4E4169AC1BE7" xml:space="preserve">virtual void AbsoluteTimerExpired() = 0;</codeblock> <p><b>When is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C6F792DB-1EC0-33F4-8F82-AB3F7B44B061"><apiname>DPowerController::AbsoluteTimerExpired()</apiname></xref> is
called by the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power
manager</xref> whenever an absolute timer expires. An absolute timer is one
that is set to complete at a specific time, as queued by a call to <xref href="GUID-8A423EA2-4264-30C9-9579-0466994E6E88.dita#GUID-8A423EA2-4264-30C9-9579-0466994E6E88/GUID-3F302410-5CC2-3CCB-82F4-47E953E7A29B"><apiname>RTimer::At()</apiname></xref>. </p> <p><b>Implementation issues</b> </p> <p>If absolute timer expiration is one
of your wake-up events, then your implementation of <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C6F792DB-1EC0-33F4-8F82-AB3F7B44B061"><apiname>DPowerController::AbsoluteTimerExpired()</apiname></xref> should
call <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-C193F898-2C15-3C42-8353-14F00789BCDA"><apiname>DPowerController::WakeupEvent()</apiname></xref> to notify the power
manager that a wake-up event has happened. </p> <p>It is recommended that
you track absolute timers. </p> </section>
<section id="GUID-1F77C71C-D226-58BB-ABAE-43F958CC0C61"><title>DPowerController::PowerDown()</title> <codeblock id="GUID-AD394AD5-8E3E-5FE3-938E-639C4E5E9F79" xml:space="preserve">virtual void PowerDown(TTimeK aWakeupTime) = 0;</codeblock> <p><b>When is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-8AE99718-6B82-3920-9029-28C2041A3B10"><apiname>DPowerController::PowerDown()</apiname></xref> is
called by the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power
manager</xref> to move the device into one of the system-wide low power states: <i>Standby</i> or <i>Off</i>. </p> <p>Typically,
this is a result of the user side entity that is responsible for moving the
device into a low power state calling <xref href="GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87.dita#GUID-15D25C07-CFD2-32CE-AD22-E17D512D8E87/GUID-7C6F3F0F-319B-3DEE-81BF-1EB5BB2EAB0A"><apiname>Power::PowerDown()</apiname></xref> in
the user side interface to the <xref href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita#GUID-0C435514-EEC6-5660-BB5F-535790349632/GUID-330F07B2-BBDF-5675-B7D5-FF6B25DD03F4">power
manager</xref>. </p> <p>If <xref href="GUID-26621CA5-B686-53FB-AF3E-96CDD38C8520.dita">physical
RAM defragmentation</xref> is implemented you may wish to include calls to <xref href="GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262.dita#GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262/GUID-B4825007-E3DB-3559-9D58-637150EF3DB9"><apiname> TRamDefragRequest::DefragRam()</apiname></xref> within
this function to enable defragmentation of RAM zones that can then be powered
down. </p> <p><b>Context</b> </p> <p>The
target state is defined by the value of the <codeph>iTargetState</codeph> member
of <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref>, as set by the power manager. </p> <p><b>Implementation issues</b> </p> <p>Implementation depends on the target
state: </p> <ul>
<li id="GUID-0473B5C1-BEC0-5276-88C5-A4A8379A4621"><p>if the target state
is <i>Standby</i>, as implied by a value of <xref href="GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0.dita#GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0/GUID-5604F598-8CBC-3A94-865F-CA58DA4492B0"><apiname>TPowerState::EPwStandby</apiname></xref> in <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-86A0C14F-B219-3E0B-BD5E-A2C20EEDBF64"><apiname>DPowerController::iTargetState</apiname></xref>,
then the power controller should put the hardware into a state corresponding
to the <i>Standby</i> state. </p> <p>If at least one wake-up event has been
detected and recorded since the last call to <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-0642129D-05F2-3AB0-B562-37A7BB7A275F"><apiname>DPowerController::EnableWakeupEvents()</apiname></xref>,
then <codeph>PowerDown()</codeph> should return immediately; otherwise, it
should continue with the process of putting the device into <i>Standby</i>;
execution of the function will halt, and can only continue, and return, when
a wake-up event occurs. </p> </li>
<li id="GUID-E38B9334-CFE4-5E91-9DD4-D7A0678AF344"><p>if the target state
is <i>Off</i>, as implied by a value of <xref href="GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0.dita#GUID-87AB8B20-04EE-31D2-8F3D-EA904D05B8D0/GUID-0DAD6E93-BD08-3C90-BCE8-ADBFC2681227"><apiname>TPowerState::EPwOff</apiname></xref> in <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-86A0C14F-B219-3E0B-BD5E-A2C20EEDBF64"><apiname>DPowerController::iTargetState</apiname></xref>,
then <codeph>PowerDown()</codeph> must <i>never</i> return. Typically, the
power controller turns the device off, but can choose to perform other device-specific
action such as a system reboot. </p> </li>
</ul> <p>The <xref href="GUID-8C6E2996-24DE-3E59-927A-46D32290225E.dita"><apiname>TTimeK</apiname></xref> parameter passed to the function is
a system time value. If non-zero, it specifies the time when the system should
wakeup. The kernel calculates it as the time that the next absolute timer
expires. Typically, your implementation will use the Real Time Clock module
to generate an event at the specified time, and this will cause a return to
the <i>Active</i> state. This implies that the base port should enable Real
Time Clock event detection during <i>Standby</i>. </p> <p>The Symbian definition
of the <i>Standby</i> state usually translates into the hardware manufacturer’s
CPU “Standby” or “Sleep” modes of operation. Typically, the internal clocks
associated with the core and some of the core peripherals, or their power
supply, are suppressed, and their internal state is not preserved. In this
case, the state of the core and core peripherals should be saved before going
into <i>Standby</i> so that they can be restored when the system wakes-up.
Note the following: </p> <ul>
<li id="GUID-824D88FD-33FB-50DC-A904-F5F44BFBF90A"><p>for the core state,
save the current mode, the banked registers for each mode, and the stack pointer
for both the current mode and user mode </p> </li>
<li id="GUID-E8CDFA98-E6F2-5D48-987F-E2591DAB242B"><p>for the core peripherals,
save the state of the interrupt controller, the pin function controller, the
bus state controller, and the clock controller </p> </li>
<li id="GUID-90BEA663-F58C-5AD7-8578-353E5EFFBCCC"><p>for the MMU state, save
the control register, the translation table base address, and the domain access
control, if this is supported </p> </li>
<li id="GUID-68AB9558-5CC7-573F-8A33-A38F16EAF304"><p>flush the data cache
and drain the write buffer. </p> </li>
</ul> <p>If all of this data is saved to a DRAM device, then this should be
put into self refresh mode. </p> <p>Peripherals modules involved in the detection
of wake-up events should be left powered. </p> <p>Tick timer events should
be disabled, and the current count of this and any other system timers should
be saved; relevant wake-up events should be left unmasked, and any others
should be disabled. </p> </section>
<section id="GUID-E2A072D0-A67F-5E6D-81ED-CFD77B6ED4F1"><title>DPowerController::CpuIdle()</title> <codeblock id="GUID-0E6F1B1D-F979-575B-BA3C-096CE4C0CA15" xml:space="preserve">virtual void CpuIdle()=0;</codeblock> <p><b>When is it called?</b> </p> <p> <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita#GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366/GUID-473874CA-FC35-3EB2-BC23-A97D7176B833"><apiname>DPowerController::CpuIdle()</apiname></xref> is
called whenever the Null thread is scheduled to run. This can happen as soon
as the power model has been installed. It is the mechanism through which your
base port can increase power savings when the system becomes inactive by moving
the CPU or the system into a low power mode. </p> <p>If <xref href="GUID-26621CA5-B686-53FB-AF3E-96CDD38C8520.dita">physical
RAM defragmentation</xref> is implemented you may wish to include calls to <xref href="GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262.dita#GUID-AE7E0A8E-1513-3F6B-A6D5-150084C4E262/GUID-B4825007-E3DB-3559-9D58-637150EF3DB9"><apiname> TRamDefragRequest::DefragRam()</apiname></xref> within
this function to enable defragmentation while the device is idle. </p> <p><b>Implementation issues</b> </p> <p>The implementation can call the Variant
or ASSP implementation of <xref href="GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D.dita#GUID-A83A7C3C-7DC0-3B9C-842F-70FCC751365D/GUID-6F242C0C-2EFC-30EC-9A5E-A34C8D15E0D7"><apiname>Asic::Idle()</apiname></xref>. </p> <p>The idle
state is usually implemented via a Wait-For-Interrupt type instruction that
will usually suspend execution of the CPU, possibly triggering other ASIC
power saving actions, and will resume execution when any unmasked interrupt
occurs. </p> <p><b>Suppressing
the system tick interrupt</b> </p> <p>To further increase power savings during
CPU Idle, a base port can choose to suppress the system tick interrupt until
the next nanokernel Timer (as implemented by <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref>) is
due to expire. Nanokernel timers are the basic timing service and all Symbian
platform tick-based timers and time-of-day functions are derived from nanokernel
timers. </p> <p>In EKA2, timing services rely on a hardware timer, which is
programmed by the base port Variant code, to generate the system tick. We
refer to this as the <i>system timer</i>. </p> <p>Typically, the platform-specific
ASSP or Variant object has a pointer to the nanokernel timer queue, an <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita"><apiname>NTimerQ</apiname></xref> object.
The number of ticks before the next <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> is due to expire
can be found by calling <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita#GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0/GUID-69103F26-2C21-3ECA-9DB5-C31A41F6C238"><apiname>NTimerQ::IdleTime()</apiname></xref>. </p> <p>Before
going into Idle mode, <codeph>CpuIdle()</codeph> disables the hardware timer
used to generate the system tick (i.e. the system timer) for the number of
ticks to be suppressed; i.e. the system timer is reset to go off and generate
an interrupt only when the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expires. Note that the
clock supply to the hardware timer must be left enabled. </p> <p>On returning
from Idle mode, the software must examine the system timer and decide whether
the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration was responsible for waking up the
processor, or whether it was due to some other interrupt. </p> <p>If waking
up was due to the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref>, the system timer must be reset
to generate the system tick at the frequency desired, and the tick count, <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita#GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0/GUID-ACFDFE7C-19AE-3C81-9D38-3266A3A3EF1F"><apiname>NTimerQ::iMsCount</apiname></xref>,
must be adjusted with the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration time. As the
expiration time is always an integer multiple of the number of ticks, then
the <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita#GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0/GUID-AA1EC86F-8A6E-340D-848F-A86554772A13"><apiname>NTimerQ::Advance()</apiname></xref> function can be used for this purpose. </p> <p>If
waking up was due to another interrupt, then the software must read the system
timer and calculate the time elapsed since going into Idle mode, and adjust
the system tick count with the elapsed time (which could be a fractional number
of ticks) and reprogram the system timer to continue generating the tick after
the correct interval, as above. </p> <p>If the hardware timer that is used
to generate the system ticks does not use a Compare-Match function, then some
care has to be taken not to introduce skewing when manipulating the timer
value directly. If the timer needs to be reloaded with the new value to give
the next tick, then the software usually “spins”, waiting for the hardware
timer to change, and then reloads it. This way the timer will always be reloaded
on an edge of its internal clock. </p> <p><b>Waking
up from “Sleep” modes with long wakeup latencies</b> </p> <p>Often, to further
enhance power savings, the CPU and some peripherals are moved into a hardware
“sleep” mode when <codeph>CpuIdle()</codeph> is called. This could be of long
latency, and waking up could take longer than the system Tick period. There
are two situations: </p> <ul>
<li id="GUID-7484F7CB-C824-5752-9043-736E95D4405D"><p>if the wakeup time can
be determined precisely, then <codeph>CpuIdle()</codeph> programs the system
timer to bring the CPU back from the “Sleep“ mode at a time corresponding
to the next <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration (as a number of Ticks to
suppress) <i>minus</i> the number of ticks it takes to wake up from that mode.
On waking up on the timer, the System tick count should be adjusted with the
total number of ticks suppressed, i.e. the count corresponding to the time
of the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration. </p> </li>
<li id="GUID-C0A9B2A2-D98D-50C0-B58A-4E84FCEC12E4"><p>If the wakeup time cannot
be known deterministically, then the above scheme must be combined with another
system to allow adjusting the system timer from the hardware Real Time Clock
(RTC). </p> <p>Typically, the hardware RTC is clocked with a 1Hz clock, and
can be programmed to interrupt the CPU on multiples of one second intervals.
The clock supply to the RTC must be left enabled on going into "sleep" mode. </p> </li>
</ul> <p>To guarantee that timed events occur when they are due, the CPU should
only be allowed to go to into the long latency hardware “sleep” mode if the
RTC can be guaranteed to complete a second tick before the CPU is due to wakeup. </p> <p>Note
that if waking up from hardware “Sleep” mode takes a non-negligible amount
of time, extreme care should be taken when deciding to move the platform into
that mode. For example, if a receive request is pending on a data input device <i>and</i> the
CPU reaches the Idle mode <i>and</i> the platform is transitioned into a “sleep”
state <i>and</i> data arrives while it is still in that state, <i>then</i> there
is a possibility that the system will not wake up on time to service the incoming
data. </p> </section>
<section id="GUID-4B613C67-3A12-4AD5-8842-6ED510A68746"><title>Validation</title> <p>The <filepath>e32test</filepath> programs <filepath>t_power</filepath>, and <filepath>t_timer</filepath> will put the system into standby and resume
off a timer. </p> </section>
</conbody><related-links>
<link href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita"><linktext>Power Management</linktext>
</link>
</related-links></concept>