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