author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Tue, 31 Aug 2010 16:34:26 +0300 | |
branch | RCL_3 |
changeset 43 | c1f20ce4abcf |
parent 0 | a41df078684a |
child 44 | 3e88ff8f41d5 |
permissions | -rw-r--r-- |
0 | 1 |
// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). |
2 |
// All rights reserved. |
|
3 |
// This component and the accompanying materials are made available |
|
4 |
// under the terms of the License "Eclipse Public License v1.0" |
|
5 |
// which accompanies this distribution, and is available |
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 |
// |
|
8 |
// Initial Contributors: |
|
9 |
// Nokia Corporation - initial contribution. |
|
10 |
// |
|
11 |
// Contributors: |
|
12 |
// |
|
13 |
// Description: |
|
14 |
// template\template_variant\specific\power.cpp |
|
15 |
// Template Power Management |
|
16 |
// (see also variant.cpp for a discussion on Sleep modes and xyin.cpp for example |
|
17 |
// of usage of Resource Manager and Peripheral self power down and interaction |
|
18 |
// with Power Controller for Wakeup Events) |
|
19 |
// |
|
20 |
// |
|
21 |
||
22 |
#include "template_power.h" |
|
23 |
||
24 |
static TemplateResourceManager TheResourceManager; |
|
25 |
||
26 |
DTemplatePowerController* TTemplatePowerController::iPowerController; |
|
27 |
||
28 |
||
29 |
//-/-/-/-/-/-/-/-/-/ class DTemplatePowerController /-/-/-/-/-/-/-/-/-/ |
|
30 |
||
31 |
DTemplatePowerController::DTemplatePowerController() |
|
32 |
{ |
|
33 |
Register(); // register Power Controller with Power Manager |
|
34 |
TTemplatePowerController::RegisterPowerController(this); |
|
35 |
} |
|
36 |
||
37 |
void DTemplatePowerController::CpuIdle() |
|
38 |
{ |
|
39 |
Arch::TheAsic()->Idle(); |
|
40 |
} |
|
41 |
||
42 |
void DTemplatePowerController::EnableWakeupEvents() |
|
43 |
{ |
|
44 |
// |
|
45 |
// TO DO: (mandatory) |
|
46 |
// |
|
47 |
// Enable tracking of wake-up events directly in hardware. If the hardware is controlled by a Driver |
|
48 |
// or Extension, may need to disable interrupts and preemption around the code that accesses the hardware |
|
49 |
// and set up a flag which the Driver/Extension code need to read before modifying the state of that piece |
|
50 |
// of hardware. Note in that case the Driver/Extension may need to link to this Library. |
|
51 |
// |
|
52 |
||
53 |
// |
|
54 |
// EXAMPLE ONLY |
|
55 |
// In this example we simply assume that the driver will call the Power Controller every time a |
|
56 |
// wakeup event occurr. It is up to the Power Controller to know if it is tracking them or not. |
|
57 |
// We also assume that if a wakeup event occurrs when the CPU is in Standby, this will automatically |
|
58 |
// bring it back from that state. |
|
59 |
iWakeupEventsOn = ETrue; // start tracking wakeup events |
|
60 |
} |
|
61 |
||
62 |
void DTemplatePowerController::DisableWakeupEvents() |
|
63 |
{ |
|
64 |
// |
|
65 |
// TO DO: (mandatory) |
|
66 |
// |
|
67 |
// Disable tracking of wake-up events directly in hardware or if the hardware is controlled by a Driver or |
|
68 |
// Extension need to set up a flag which the Driver/Extension reads whenever the event occurs, in order to |
|
69 |
// find out if it needs to deliver notification to the Power Controller |
|
70 |
// |
|
71 |
iWakeupEventsOn = EFalse; // stop tracking wakeup events |
|
72 |
} |
|
73 |
||
74 |
void DTemplatePowerController::AbsoluteTimerExpired() |
|
75 |
{ |
|
76 |
if (iTargetState == EPwStandby && iWakeupEventsOn) |
|
77 |
{ |
|
78 |
iWakeupEventsOn = EFalse; // one occurred, no longer track wakeup events |
|
79 |
WakeupEvent(); |
|
80 |
} |
|
81 |
} |
|
82 |
||
83 |
void DTemplatePowerController::PowerDown(TTimeK aWakeupST) |
|
84 |
{ |
|
85 |
if (iTargetState == EPwStandby) |
|
86 |
{ |
|
87 |
// |
|
88 |
// TO DO: (mandatory) |
|
89 |
// |
|
90 |
// Converts between the Wakeup time in System Time units as passed in to this function and a Wakeup |
|
91 |
// time in RTC units. The following code is given as an example how to convert between System time units |
|
92 |
// RTC time units on a system with a 32 bit RTC timer and which is incremented on a second interval: |
|
93 |
// |
|
94 |
TUint32 wakeupRTC; |
|
95 |
if (aWakeupST) |
|
96 |
{ |
|
97 |
TUint32 nowRTC = TTemplate::RtcData(); |
|
98 |
TTimeK nowST = Kern::SystemTime(); |
|
99 |
__KTRACE_OPT(KPOWER,Kern::Printf("system time: now = 0x%lx(us) wakeup = 0x%lx(us)", nowST, aWakeupST)); |
|
100 |
if (aWakeupST < nowST) |
|
101 |
return; |
|
102 |
Int64 deltaSecs = (aWakeupST - nowST) / 1000000; |
|
103 |
if (deltaSecs <= 0) |
|
104 |
return; |
|
105 |
if (deltaSecs + (Int64)nowRTC > (Int64)(KMaxTInt - 2)) |
|
106 |
wakeupRTC = (KMaxTInt - 2); // RTC can't wrap around during standby |
|
107 |
else |
|
108 |
wakeupRTC = nowRTC + deltaSecs; |
|
109 |
__KTRACE_OPT(KPOWER,Kern::Printf("RTC: now = %d(s) wakeup = %d(s)", nowRTC, wakeupRTC)); |
|
110 |
} |
|
111 |
else |
|
112 |
wakeupRTC = 0; |
|
113 |
// |
|
114 |
// TO DO: (optional) |
|
115 |
// |
|
116 |
// It then uses the calculated value to program the RTC to wakeup the System at the Wakeup |
|
117 |
// time ans sets the CPU and remaining hardware to go to the correponding low power mode. When the |
|
118 |
// state of the Core and Core Peripherals is not preserved in this mode the following is usually |
|
119 |
// required: |
|
120 |
// - save current Core state (current Mode, banked registers for each Mode and Stack Pointer for |
|
121 |
// both current and User Modes |
|
122 |
// - save MMU state: Control Register, TTB and Domain Access Control |
|
123 |
// - Flush Dta Cache and drain Write Buffer |
|
124 |
// - save Core Peripherals state: Interrupt Controller, Pin Function, Bus State and Clock settings |
|
125 |
// SDRAM should be put in self refresh mode. Peripheral devices involved in detection of Wakeup events |
|
126 |
// should be left powered. |
|
127 |
// The Tick timer should be disabled and the current count of this and other System timers shall be |
|
128 |
// saved. |
|
129 |
// On wakeing up the state should be restored from the save state as above. SDRAM shall be brought back |
|
130 |
// under CPU control, The Tick count shall be restored and timers re-enabled. |
|
131 |
||
132 |
// We assume that if a wakeup event occurrs when the CPU is in Standby, this will automatically |
|
133 |
// bring it back from that state. Therefore we stop tracking wakeup events as the Power Manager will |
|
134 |
// complete any pending notifications anyway. When the driver delivers its notification, we just ignore |
|
135 |
// it. |
|
43
c1f20ce4abcf
Revision: 201035
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
136 |
|
c1f20ce4abcf
Revision: 201035
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
137 |
if(wakeupRTC) |
c1f20ce4abcf
Revision: 201035
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
138 |
{ |
c1f20ce4abcf
Revision: 201035
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
139 |
//Handle this if needed |
c1f20ce4abcf
Revision: 201035
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
140 |
} |
c1f20ce4abcf
Revision: 201035
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
141 |
|
0 | 142 |
iWakeupEventsOn = EFalse; // tracking of wakeup events is now done in hardware |
143 |
} |
|
144 |
else |
|
145 |
{ |
|
146 |
Kern::Restart(0x80000000); |
|
147 |
} |
|
148 |
} |
|
149 |
||
150 |
//-/-/-/-/-/-/-/-/-/ class TTemplatePowerController /-/-/-/-/-/-/-/-/-/ |
|
151 |
||
152 |
EXPORT_C TemplateResourceManager* TTemplatePowerController::ResourceManager() |
|
153 |
{ |
|
154 |
return &TheResourceManager; |
|
155 |
} |
|
156 |
||
157 |
||
158 |
EXPORT_C void TTemplatePowerController::WakeupEvent() |
|
159 |
{ |
|
160 |
if(!iPowerController) |
|
161 |
__PM_PANIC("Power Controller not present"); |
|
162 |
else if(iPowerController->iWakeupEventsOn) |
|
163 |
{ |
|
164 |
iPowerController->iWakeupEventsOn=EFalse; // one occurred, no longer track wakeup events |
|
165 |
iPowerController->WakeupEvent(); |
|
166 |
} |
|
167 |
} |
|
168 |
||
169 |
//-/-/-/-/-/-/-/-/-/ class TemplateResourceManager /-/-/-/-/-/-/-/-/-/ |
|
170 |
||
171 |
void TemplateResourceManager::InitResources() |
|
172 |
{ |
|
173 |
// |
|
174 |
// TO DO: (optional) |
|
175 |
// |
|
176 |
// Initialise any power resources required by the platform and not initialised in the Bootstrap |
|
177 |
// |
|
178 |
} |
|
179 |
||
180 |
//-/-/-/-/-/-/-/-/-/ interface for shared resources /-/-/-/-/-/-/-/-/-/ |
|
181 |
||
182 |
void SharedBinaryResource1::Use() |
|
183 |
{ |
|
184 |
NKern::Lock(); // lock Kernel as shared resource is likely to be modified from different threads |
|
185 |
if (iCount++ == 0) |
|
186 |
{ |
|
187 |
// |
|
188 |
// TO DO: (optional) |
|
189 |
// |
|
190 |
// Modify hardware register bit or bits to switch the resource On. If the resource |
|
191 |
// can be accessed from an ISR need to disable/enable interrupts around it. |
|
192 |
// |
|
193 |
NKern::Unlock(); |
|
194 |
// |
|
195 |
// TO DO: (optional) |
|
196 |
// |
|
197 |
// If the resource is asynchronous may need to sleep or block the thread until the change is complete |
|
198 |
// |
|
199 |
} |
|
200 |
else |
|
201 |
NKern::Unlock(); |
|
202 |
} |
|
203 |
||
204 |
void SharedBinaryResource1::Release() |
|
205 |
{ |
|
206 |
NKern::Lock(); |
|
207 |
__PM_ASSERT(iCount); |
|
208 |
if (--iCount == 0) |
|
209 |
{ |
|
210 |
// |
|
211 |
// TO DO: (optional) |
|
212 |
// |
|
213 |
// Modify hardware register bit or bits to switch the resource Off. If the resource |
|
214 |
// can be accessed from an ISR need to disable/enable interrupts around it. |
|
215 |
// |
|
216 |
NKern::Unlock(); |
|
217 |
// |
|
218 |
// TO DO: (optional) |
|
219 |
// |
|
220 |
// If the resource is asynchronous may need to sleep or block the thread until the change is complete |
|
221 |
// |
|
222 |
} |
|
223 |
else |
|
224 |
NKern::Unlock(); |
|
225 |
} |
|
226 |
||
227 |
TUint SharedBinaryResource1::GetCount() |
|
228 |
{ |
|
229 |
return iCount; |
|
230 |
} |
|
231 |
||
232 |
SharedMultilevelResource1::SharedMultilevelResource1() |
|
233 |
// |
|
234 |
// TO DO: (optional) |
|
235 |
// |
|
236 |
// May need to initialise current level and the Id of its owner if these have been initialised in the Bootstrap |
|
237 |
// |
|
238 |
// : iCurrentLevel(/* a level for this resource as initialised in the Bootstrap */), |
|
239 |
// iCurrentLevelOwnerId(/* the Id of the requester of this resource that requires the initial value */) |
|
240 |
{ |
|
241 |
} |
|
242 |
||
243 |
void SharedMultilevelResource1::IncreaseToLevel(TUint aLevel, TInt aRequester) |
|
244 |
{ |
|
245 |
// |
|
246 |
// Drivers should use this API if they wish to request a level higher than the previous level they required |
|
247 |
// Drivers should keep track of the level they require and be disciplined |
|
248 |
// |
|
249 |
NKern::Lock(); |
|
250 |
__PM_ASSERT(aLevel<Levels[aRequester]); |
|
251 |
Levels[aRequester]=aLevel; |
|
252 |
if(aLevel > iCurrentLevel) // need to increase the level |
|
253 |
{ |
|
254 |
// if(aLevel <= MAXLEVEL) |
|
255 |
// aLevel = MAXLEVEL; |
|
256 |
iCurrentLevel = aLevel; |
|
257 |
iCurrentLevelOwnerId = aRequester; |
|
258 |
// |
|
259 |
// TO DO: (optional) |
|
260 |
// |
|
261 |
// Modify hardware register bits to set the level of the resource to aLevel |
|
262 |
NKern::Unlock(); |
|
263 |
// |
|
264 |
// TO DO: (optional) |
|
265 |
// |
|
266 |
// If the resource is asynchronous may need to sleep or block the thread until the change is complete |
|
267 |
// |
|
268 |
} |
|
269 |
else |
|
270 |
NKern::Unlock(); |
|
271 |
} |
|
272 |
||
273 |
void SharedMultilevelResource1::ReduceToLevel(TUint aLevel, TInt aRequester) |
|
274 |
{ |
|
275 |
// |
|
276 |
// Drivers should use this API if they wish to request a level higher than the previous level they required |
|
277 |
// |
|
278 |
NKern::Lock(); |
|
279 |
__PM_ASSERT(aLevel>Levels[aRequester]); |
|
280 |
||
281 |
Levels[aRequester]=aLevel; |
|
282 |
if(aLevel < iCurrentLevel && aRequester == iCurrentLevelOwnerId) // the holder of the current level as lowered its request |
|
283 |
{ |
|
284 |
FindMaxLevel(&iCurrentLevel, &iCurrentLevelOwnerId); // find max level required and the ID of its holder |
|
285 |
// |
|
286 |
// TO DO: (optional) |
|
287 |
// |
|
288 |
// Modify hardware register bits to set the level of the resource to iCurrentLevel |
|
289 |
NKern::Unlock(); |
|
290 |
// |
|
291 |
// TO DO: (optional) |
|
292 |
// |
|
293 |
// If the resource is asynchronous may need to sleep or block the thread until the change is complete |
|
294 |
// |
|
295 |
} |
|
296 |
else |
|
297 |
NKern::Unlock(); |
|
298 |
} |
|
299 |
||
300 |
TUint SharedMultilevelResource1::GetResourceLevel() |
|
301 |
{ |
|
302 |
return iCurrentLevel; |
|
303 |
} |
|
304 |
||
305 |
void SharedMultilevelResource1::FindMaxLevel(TUint* aLevel, TInt* aId) |
|
306 |
{ |
|
307 |
// |
|
308 |
// TO DO: (optional) |
|
309 |
// |
|
310 |
// Place your clever array search algorithm here... |
|
311 |
// return max level and id of owner |
|
312 |
} |
|
313 |
||
314 |
TInt BinaryPowerInit(); // the Symbian example Battery Monitor and Power HAL handling |
|
315 |
||
316 |
GLDEF_C TInt KernelModuleEntry(TInt aReason) |
|
317 |
{ |
|
318 |
if(aReason==KModuleEntryReasonVariantInit0) |
|
319 |
{ |
|
320 |
// |
|
321 |
// TO DO: (optional) |
|
322 |
// |
|
323 |
// Start the Resource Manager earlier so that Variant and other extension could make use of Power Resources |
|
324 |
// |
|
325 |
__KTRACE_OPT(KPOWER, Kern::Printf("Starting Template Resource controller")); |
|
326 |
new(&TheResourceManager)TemplateResourceManager; |
|
327 |
TheResourceManager.InitResources(); |
|
328 |
return KErrNone; |
|
329 |
} |
|
330 |
else if(aReason==KModuleEntryReasonExtensionInit0) |
|
331 |
{ |
|
332 |
__KTRACE_OPT(KPOWER, Kern::Printf("Starting Template power controller")); |
|
333 |
// |
|
334 |
// TO DO: (optional) |
|
335 |
// |
|
336 |
// Start the Kernel-side Battery Monitor and hook a Power HAL handling function. |
|
337 |
// Symbian provides example code for both of the above in \e32\include\driver\binpower.h |
|
338 |
// You may want to write your own versions. |
|
339 |
// The call below starts the example Battery Monitor and hooks the example Power HAL handling function |
|
340 |
// At the end we return an error to make sure that the entry point is not called again with |
|
341 |
// KModuleEntryReasonExtensionInit1 (which would call the constructor of TheResourceManager again) |
|
342 |
// |
|
343 |
TInt r = BinaryPowerInit(); |
|
344 |
if (r!= KErrNone) |
|
345 |
__PM_PANIC("Can't initialise Binary Power model"); |
|
346 |
DTemplatePowerController* c = new DTemplatePowerController(); |
|
347 |
if(c) |
|
348 |
return KErrGeneral; |
|
349 |
else |
|
350 |
__PM_PANIC("Can't create Power Controller"); |
|
351 |
} |
|
352 |
else if(aReason==KModuleEntryReasonExtensionInit1) |
|
353 |
{ |
|
354 |
// does not get called... |
|
355 |
} |
|
356 |
return KErrArgument; |
|
357 |
} |