|
1 <?xml version="1.0" encoding="utf-8"?> |
|
2 <!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. --> |
|
3 <!-- This component and the accompanying materials are made available under the terms of the License |
|
4 "Eclipse Public License v1.0" which accompanies this distribution, |
|
5 and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". --> |
|
6 <!-- Initial Contributors: |
|
7 Nokia Corporation - initial contribution. |
|
8 Contributors: |
|
9 --> |
|
10 <!DOCTYPE concept |
|
11 PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd"> |
|
12 <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 |
|
13 port.</shortdesc><prolog><metadata><keywords/></metadata></prolog><conbody> |
|
14 <p><xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> is defined as: </p> |
|
15 <codeblock id="GUID-95318C39-B205-557C-B1F3-75C1441E464A" xml:space="preserve">class DPowerController : public DBase |
|
16 { |
|
17 public: |
|
18 IMPORT_C DPowerController(); |
|
19 IMPORT_C void Register(); |
|
20 IMPORT_C void WakeupEvent(); |
|
21 |
|
22 #ifndef __X86__ |
|
23 IMPORT_C TInt RegisterResourceController(DBase* aController, TInt aClientId); |
|
24 private: |
|
25 struct SResourceControllerData |
|
26 { |
|
27 DBase* iResourceController; |
|
28 TInt iClientId; |
|
29 } iResourceControllerData; |
|
30 #endif |
|
31 |
|
32 public: |
|
33 volatile TPowerState iTargetState; |
|
34 public: |
|
35 virtual void CpuIdle() = 0; |
|
36 virtual void EnableWakeupEvents() = 0; |
|
37 virtual void DisableWakeupEvents() = 0; |
|
38 virtual void AbsoluteTimerExpired() = 0; |
|
39 virtual void PowerDown(TTimeK aWakeupTime) = 0; |
|
40 }; |
|
41 </codeblock> |
|
42 <p>The first three functions are exported from the kernel, <filepath>EKERN.EXE</filepath>, while the other five pure virtual functions |
|
43 are implemented by your base port. You do not need to export any other |
|
44 functions. </p> |
|
45 <ul> |
|
46 <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> |
|
47 <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> |
|
48 <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> |
|
49 <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> |
|
50 <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> |
|
51 <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> |
|
52 </ul> |
|
53 <section id="GUID-BCCDBA09-415D-5779-BCE5-CDEB2E1EF7D8"><title>Initialising |
|
54 the power controller</title> <p>Typically, you implement your derived |
|
55 class in a power management kernel extension, which has the opportunity |
|
56 to perform initialisation before the system itself is fully initialised. |
|
57 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 |
|
58 your initialisation code. There are at least three things to do here: </p> <ul> |
|
59 <li id="GUID-25C66F1B-6B2F-5B3B-A827-410263EE22A4"><p>create an instance |
|
60 of your power controller object </p> </li> |
|
61 <li id="GUID-369A09EC-74D3-529A-AC05-0EFE0C4ABBF7"><p>register your |
|
62 power controller object with the Symbian platform power manager, by |
|
63 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 |
|
64 controller cannot be used by the Symbian platform power manager until |
|
65 it has been registered. </p> </li> |
|
66 <li id="GUID-E4C7D934-AAB9-511B-93A4-125D5A5B248D"><p>if you intend |
|
67 to use a battery monitor, then you would create it and register it |
|
68 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 |
|
69 Tutorial</xref> for more detail. </p> </li> |
|
70 </ul> <p>For example: </p> <codeblock id="GUID-1A909C4C-DCAF-54E3-B482-16918E33BF4F" xml:space="preserve">DECLARE_STANDARD_EXTENSION() |
|
71 { |
|
72 TInt r=KErrNoMemory; |
|
73 |
|
74 // Create the power controller object, and register it. |
|
75 DPowerController* pC = new DYourPowerController; |
|
76 if !(pC) |
|
77 { |
|
78 return (r); |
|
79 } |
|
80 pC->Register(); |
|
81 |
|
82 // Create the battery monitor. |
|
83 DBatteryMonitor* pM = new DYourBatteryMonitor; |
|
84 if !(pM) |
|
85 { |
|
86 return(r); |
|
87 } |
|
88 |
|
89 r = KErrNone; |
|
90 return(r); |
|
91 }</codeblock> </section> |
|
92 <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 |
|
93 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 |
|
94 document. </p> <p>To support idle power management the Power Controller's |
|
95 PSL must override <codeph>RegisterResourceController()</codeph> to |
|
96 include the registration of a list of resources whose states are of |
|
97 interest to idle power management. </p> <p><b>Idle power management</b> </p> <p>The Power Controller can assemble |
|
98 a list of resources whose state it is interested in from a NULL thread |
|
99 in an array of <xref href="GUID-586AF75A-8350-345D-ABF4-6542C8E75DED.dita"><apiname>SIdleResourceInfo</apiname></xref> structures. Each |
|
100 entry in the list contains the resource ID that the power controller |
|
101 must enter before registering with the PRM. The resource list should |
|
102 be created in the kernel heap or data section. </p> <p>The example |
|
103 below creates a buffer to capture the state of all static resources. |
|
104 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"> ... |
|
105 //Allocate buffer for Idle resource management |
|
106 NKern::ThreadEnterCS(); |
|
107 pBuf = HBuf::New(numResources * sizeof(SIdleResourceInfo)); |
|
108 NKern::ThreadLeaveCS(); |
|
109 if(!pBuf) |
|
110 { |
|
111 return KErrNoMemory; |
|
112 } |
|
113 SIdleResourceInfo* pI = (SIdleResourceInfo*)pBuf->Ptr(); |
|
114 |
|
115 //Update resource ID |
|
116 for(TUint c = 0; c < numResources; c++) |
|
117 { |
|
118 pI[c].iResourceId = c+1; |
|
119 } |
|
120 r = (iResourceControllerData.iResourceController)->RegisterResourcesForIdle(iResourceControllerData.iClientId, numResources, (TPtr*)pI); |
|
121 ...</codeblock> <p>The first parameter passed to <codeph>RegisterResourcesForIdle()</codeph> is the client Id generated for the power controller this is the |
|
122 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 |
|
123 to register resources for idle power management. <b>Note</b>: <codeph>RegisterResourcesForIdle()</codeph> can only be called by the Power |
|
124 Controller once. </p> </section> |
|
125 <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 |
|
126 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. |
|
127 If a wake-up event occurs while the system is preparing to transition |
|
128 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 |
|
129 to the <i>Active</i> power state. Wake-up events may be different |
|
130 for different target power states. Wake-up events are platform-specific |
|
131 hardware events, and it is your base port that decides which events |
|
132 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 |
|
133 the user side entity that is responsible for moving the device into |
|
134 a low power state. </p> <p><b>Context</b> </p> <p>When the user side entity decides to move |
|
135 the device to a low power state, it sends a notification to all of |
|
136 the user side power domains registered with it, giving their applications |
|
137 a chance to save their data and state. However, before doing this, |
|
138 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 |
|
139 be informed of a wake-up event. If it is notified of a wake-up event, |
|
140 it can halt, and reverse the user side response to the power transition. </p> <fig id="GUID-ACC6E7E3-71E3-5553-B433-9017CB04513D"> |
|
141 <image href="GUID-AEDBF425-6077-4C84-A698-508291671F2B_d0e27993_href.png" placement="inline"/> |
|
142 </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 |
|
143 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. |
|
144 This means that the power controller needs the ability to detect wake-up |
|
145 events so that it can halt, and reverse the power transition. </p> <p><b>Implementation issues</b> </p> <p>There are three possibilities |
|
146 in dealing with wake-up events: </p> <ul> |
|
147 <li id="GUID-4243E6DD-C903-58DE-B125-38CEDB8B5269"><p>if wake-up events |
|
148 are not handled by specific peripheral drivers, you could set up the |
|
149 hardware so that wake-up events are recorded in a location accessible |
|
150 by the software. Prior to completing the system power transition, |
|
151 the Power controller would check the relevant hardware to see whether |
|
152 a wakeup event had occurred. On detecting a wake-up event it would |
|
153 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> |
|
154 <li id="GUID-289B86C4-A578-5A42-A0DF-70A7BF3F440E"><p>if wake-up events |
|
155 are not handled by specific peripheral drivers, you could arrange |
|
156 for wake-up events to interrupt the CPU. The code that services those |
|
157 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> |
|
158 <li id="GUID-E51BAE55-0A81-5D1F-B509-096A7F2141EF"><p>if wakeup events |
|
159 are intercepted, serviced and cleared by peripheral drivers, then |
|
160 the following outline solution could be adopted: </p> <ul> |
|
161 <li id="GUID-5C942237-BBB2-5919-8578-B55BDAFAFC9F"><p>The power controller |
|
162 would need to publish a list of wake-up events, preferably as a bit |
|
163 mask, and export an API which peripheral drivers could use to notify |
|
164 the power controller that a wake-up event has occurred. The following |
|
165 interface class could be used for this purpose: </p> <codeblock id="GUID-084F7F46-66B6-5661-85AF-57D499250886" xml:space="preserve">class TPowerController |
|
166 { |
|
167 public: |
|
168 inline static void SetPowerControllerPointer(DPowerController* apPowerController) |
|
169 { iPowerControllerPointer = apPowerController; } |
|
170 IMPORT_C static void WakeupEventOccurred(TUint aWakeupEvent); |
|
171 … // other methods if required |
|
172 private: |
|
173 DPowerController* iPowerControllerPointer; |
|
174 }; |
|
175 </codeblock> <p>The class would be implemented |
|
176 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 |
|
177 power controller object. </p> <p>Those peripheral drivers that intercept |
|
178 wake-up events would need to link to the power controller DLL (i.e. |
|
179 the power management kernel extension). </p> <p>On the occurrence |
|
180 of a wake-up event, the peripheral driver software servicing that |
|
181 event would notify the power controller by calling <codeph>WakeupEventOccurred()</codeph>, specifying the appropriate wake-up event bit(s). </p> <p>You might |
|
182 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) |
|
183 { |
|
184 if(iPowerControllerPointer->iWakeupEvents & aWakeupEvent) |
|
185 { |
|
186 iPowerControllerPointer->WakeupEvent(); |
|
187 } |
|
188 }</codeblock> <p>where <codeph>iWakeupEvents</codeph> is a data |
|
189 member defined in your <xref href="GUID-B3D1C422-6A82-3C6E-9123-1E4F598F0366.dita"><apiname>DPowerController</apiname></xref> -derived |
|
190 class that contains the bitmask representing the wake-up events. The |
|
191 bitmask groups wakeup events according to the target power state. </p> </li> |
|
192 </ul> </li> |
|
193 </ul> <p>When the peripheral driver powers down, it should leave the |
|
194 hardware that generates the wake-up event powered and enabled for |
|
195 detection. Thus, if a wake-up event of the type handled by this peripheral |
|
196 driver occurs, it will not be serviced in the normal way, but will |
|
197 be left pending until the power controller services it. </p> <p>When |
|
198 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 |
|
199 hardware directly to see whether the wakeup event has happened, or |
|
200 is happening right now, prior to transitioning the device to the target |
|
201 system-wide low power state. If the wake-up event is found to have |
|
202 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 |
|
203 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> |
|
204 <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 |
|
205 timer is one that is set to complete at a specific time, as queued |
|
206 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 |
|
207 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 |
|
208 that a wake-up event has happened. </p> <p>It is recommended that |
|
209 you track absolute timers. </p> </section> |
|
210 <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 |
|
211 low power states: <i>Standby</i> or <i>Off</i>. </p> <p>Typically, |
|
212 this is a result of the user side entity that is responsible for moving |
|
213 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 |
|
214 can then be powered down. </p> <p><b>Context</b> </p> <p>The target state is defined by the value of |
|
215 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 |
|
216 target state: </p> <ul> |
|
217 <li id="GUID-0473B5C1-BEC0-5276-88C5-A4A8379A4621"><p>if the target |
|
218 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 |
|
219 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 |
|
220 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, |
|
221 it should continue with the process of putting the device into <i>Standby</i>; execution of the function will halt, and can only continue, |
|
222 and return, when a wake-up event occurs. </p> </li> |
|
223 <li id="GUID-E38B9334-CFE4-5E91-9DD4-D7A0678AF344"><p>if the target |
|
224 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 |
|
225 controller turns the device off, but can choose to perform other device-specific |
|
226 action such as a system reboot. </p> </li> |
|
227 </ul> <p>The <xref href="GUID-8C6E2996-24DE-3E59-927A-46D32290225E.dita"><apiname>TTimeK</apiname></xref> parameter passed to the function |
|
228 is a system time value. If non-zero, it specifies the time when the |
|
229 system should wakeup. The kernel calculates it as the time that the |
|
230 next absolute timer expires. Typically, your implementation will use |
|
231 the Real Time Clock module to generate an event at the specified time, |
|
232 and this will cause a return to the <i>Active</i> state. This implies |
|
233 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” |
|
234 or “Sleep” modes of operation. Typically, the internal clocks associated |
|
235 with the core and some of the core peripherals, or their power supply, |
|
236 are suppressed, and their internal state is not preserved. In this |
|
237 case, the state of the core and core peripherals should be saved before |
|
238 going into <i>Standby</i> so that they can be restored when the system |
|
239 wakes-up. Note the following: </p> <ul> |
|
240 <li id="GUID-824D88FD-33FB-50DC-A904-F5F44BFBF90A"><p>for the core |
|
241 state, save the current mode, the banked registers for each mode, |
|
242 and the stack pointer for both the current mode and user mode </p> </li> |
|
243 <li id="GUID-E8CDFA98-E6F2-5D48-987F-E2591DAB242B"><p>for the core |
|
244 peripherals, save the state of the interrupt controller, the pin function |
|
245 controller, the bus state controller, and the clock controller </p> </li> |
|
246 <li id="GUID-90BEA663-F58C-5AD7-8578-353E5EFFBCCC"><p>for the MMU |
|
247 state, save the control register, the translation table base address, |
|
248 and the domain access control, if this is supported </p> </li> |
|
249 <li id="GUID-68AB9558-5CC7-573F-8A33-A38F16EAF304"><p>flush the data |
|
250 cache and drain the write buffer. </p> </li> |
|
251 </ul> <p>If all of this data is saved to a DRAM device, then this |
|
252 should be put into self refresh mode. </p> <p>Peripherals modules |
|
253 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 |
|
254 this and any other system timers should be saved; relevant wake-up |
|
255 events should be left unmasked, and any others should be disabled. </p> </section> |
|
256 <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 |
|
257 happen as soon as the power model has been installed. It is the mechanism |
|
258 through which your base port can increase power savings when the system |
|
259 becomes inactive by moving the CPU or the system into a low power |
|
260 mode. </p> <p>If <xref href="GUID-26621CA5-B686-53FB-AF3E-96CDD38C8520.dita">physical RAM defragmentation</xref> is implemented you may wish to |
|
261 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 |
|
262 is idle. </p> <p><b>Implementation issues</b> </p> <p>The implementation can call |
|
263 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 |
|
264 type instruction that will usually suspend execution of the CPU, possibly |
|
265 triggering other ASIC power saving actions, and will resume execution |
|
266 when any unmasked interrupt occurs. </p> <p><b>Suppressing the system tick interrupt</b> </p> <p>To further increase |
|
267 power savings during CPU Idle, a base port can choose to suppress |
|
268 the system tick interrupt until the next nanokernel Timer (as implemented |
|
269 by <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref>) is due to expire. Nanokernel timers |
|
270 are the basic timing service and all Symbian platform tick-based timers |
|
271 and time-of-day functions are derived from nanokernel timers. </p> <p>In EKA2, timing services rely on a hardware timer, which is programmed |
|
272 by the base port Variant code, to generate the system tick. We refer |
|
273 to this as the <i>system timer</i>. </p> <p>Typically, the platform-specific |
|
274 ASSP or Variant object has a pointer to the nanokernel timer queue, |
|
275 an <xref href="GUID-C54D99AA-FF6E-3023-8260-8F5A88FBFBE0.dita"><apiname>NTimerQ</apiname></xref> object. The number of ticks before the |
|
276 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 |
|
277 system tick (i.e. the system timer) for the number of ticks to be |
|
278 suppressed; i.e. the system timer is reset to go off and generate |
|
279 an interrupt only when the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expires. Note |
|
280 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 |
|
281 timer and decide whether the <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration |
|
282 was responsible for waking up the processor, or whether it was due |
|
283 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 |
|
284 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 |
|
285 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 |
|
286 due to another interrupt, then the software must read the system timer |
|
287 and calculate the time elapsed since going into Idle mode, and adjust |
|
288 the system tick count with the elapsed time (which could be a fractional |
|
289 number of ticks) and reprogram the system timer to continue generating |
|
290 the tick after the correct interval, as above. </p> <p>If the hardware |
|
291 timer that is used to generate the system ticks does not use a Compare-Match |
|
292 function, then some care has to be taken not to introduce skewing |
|
293 when manipulating the timer value directly. If the timer needs to |
|
294 be reloaded with the new value to give the next tick, then the software |
|
295 usually “spins”, waiting for the hardware timer to change, and then |
|
296 reloads it. This way the timer will always be reloaded on an edge |
|
297 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 |
|
298 are moved into a hardware “sleep” mode when <codeph>CpuIdle()</codeph> is called. This could be of long latency, and waking up could take |
|
299 longer than the system Tick period. There are two situations: </p> <ul> |
|
300 <li id="GUID-7484F7CB-C824-5752-9043-736E95D4405D"><p>if the wakeup |
|
301 time can be determined precisely, then <codeph>CpuIdle()</codeph> programs |
|
302 the system timer to bring the CPU back from the “Sleep“ mode at a |
|
303 time corresponding to the next <xref href="GUID-D8CF05A3-5C9B-3662-92DA-3290C6EE7FD2.dita"><apiname>NTimer</apiname></xref> expiration |
|
304 (as a number of Ticks to suppress) <i>minus</i> the number of ticks |
|
305 it takes to wake up from that mode. On waking up on the timer, the |
|
306 System tick count should be adjusted with the total number of ticks |
|
307 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> |
|
308 <li id="GUID-C0A9B2A2-D98D-50C0-B58A-4E84FCEC12E4"><p>If the wakeup |
|
309 time cannot be known deterministically, then the above scheme must |
|
310 be combined with another system to allow adjusting the system timer |
|
311 from the hardware Real Time Clock (RTC). </p> <p>Typically, the hardware |
|
312 RTC is clocked with a 1Hz clock, and can be programmed to interrupt |
|
313 the CPU on multiples of one second intervals. The clock supply to |
|
314 the RTC must be left enabled on going into "sleep" mode. </p> </li> |
|
315 </ul> <p>To guarantee that timed events occur when they are due, the |
|
316 CPU should only be allowed to go to into the long latency hardware |
|
317 “sleep” mode if the RTC can be guaranteed to complete a second tick |
|
318 before the CPU is due to wakeup. </p> <p>Note that if waking up from |
|
319 hardware “Sleep” mode takes a non-negligible amount of time, extreme |
|
320 care should be taken when deciding to move the platform into that |
|
321 mode. For example, if a receive request is pending on a data input |
|
322 device <i>and</i> the CPU reaches the Idle mode <i>and</i> the platform |
|
323 is transitioned into a “sleep” state <i>and</i> data arrives while |
|
324 it is still in that state, <i>then</i> there is a possibility that |
|
325 the system will not wake up on time to service the incoming data. </p> </section> |
|
326 <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 |
|
327 and resume off a timer. </p> </section> |
|
328 </conbody><related-links> |
|
329 <link href="GUID-0C435514-EEC6-5660-BB5F-535790349632.dita"><linktext>Power |
|
330 Management</linktext></link> |
|
331 </related-links></concept> |