Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
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)
22 #include "template_power.h"
24 static TemplateResourceManager TheResourceManager;
26 DTemplatePowerController* TTemplatePowerController::iPowerController;
29 //-/-/-/-/-/-/-/-/-/ class DTemplatePowerController /-/-/-/-/-/-/-/-/-/
31 DTemplatePowerController::DTemplatePowerController()
33 Register(); // register Power Controller with Power Manager
34 TTemplatePowerController::RegisterPowerController(this);
37 void DTemplatePowerController::CpuIdle()
39 Arch::TheAsic()->Idle();
42 void DTemplatePowerController::EnableWakeupEvents()
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.
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
62 void DTemplatePowerController::DisableWakeupEvents()
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
71 iWakeupEventsOn = EFalse; // stop tracking wakeup events
74 void DTemplatePowerController::AbsoluteTimerExpired()
76 if (iTargetState == EPwStandby && iWakeupEventsOn)
78 iWakeupEventsOn = EFalse; // one occurred, no longer track wakeup events
83 void DTemplatePowerController::PowerDown(TTimeK aWakeupST)
85 if (iTargetState == EPwStandby)
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:
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)
102 Int64 deltaSecs = (aWakeupST - nowST) / 1000000;
105 if (deltaSecs + (Int64)nowRTC > (Int64)(KMaxTInt - 2))
106 wakeupRTC = (KMaxTInt - 2); // RTC can't wrap around during standby
108 wakeupRTC = nowRTC + deltaSecs;
109 __KTRACE_OPT(KPOWER,Kern::Printf("RTC: now = %d(s) wakeup = %d(s)", nowRTC, wakeupRTC));
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
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
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.
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
136 iWakeupEventsOn = EFalse; // tracking of wakeup events is now done in hardware
140 Kern::Restart(0x80000000);
144 //-/-/-/-/-/-/-/-/-/ class TTemplatePowerController /-/-/-/-/-/-/-/-/-/
146 EXPORT_C TemplateResourceManager* TTemplatePowerController::ResourceManager()
148 return &TheResourceManager;
152 EXPORT_C void TTemplatePowerController::WakeupEvent()
154 if(!iPowerController)
155 __PM_PANIC("Power Controller not present");
156 else if(iPowerController->iWakeupEventsOn)
158 iPowerController->iWakeupEventsOn=EFalse; // one occurred, no longer track wakeup events
159 iPowerController->WakeupEvent();
163 //-/-/-/-/-/-/-/-/-/ class TemplateResourceManager /-/-/-/-/-/-/-/-/-/
165 void TemplateResourceManager::InitResources()
170 // Initialise any power resources required by the platform and not initialised in the Bootstrap
174 //-/-/-/-/-/-/-/-/-/ interface for shared resources /-/-/-/-/-/-/-/-/-/
176 void SharedBinaryResource1::Use()
178 NKern::Lock(); // lock Kernel as shared resource is likely to be modified from different threads
184 // Modify hardware register bit or bits to switch the resource On. If the resource
185 // can be accessed from an ISR need to disable/enable interrupts around it.
191 // If the resource is asynchronous may need to sleep or block the thread until the change is complete
198 void SharedBinaryResource1::Release()
207 // Modify hardware register bit or bits to switch the resource Off. If the resource
208 // can be accessed from an ISR need to disable/enable interrupts around it.
214 // If the resource is asynchronous may need to sleep or block the thread until the change is complete
221 TUint SharedBinaryResource1::GetCount()
226 SharedMultilevelResource1::SharedMultilevelResource1()
230 // May need to initialise current level and the Id of its owner if these have been initialised in the Bootstrap
232 // : iCurrentLevel(/* a level for this resource as initialised in the Bootstrap */),
233 // iCurrentLevelOwnerId(/* the Id of the requester of this resource that requires the initial value */)
237 void SharedMultilevelResource1::IncreaseToLevel(TUint aLevel, TInt aRequester)
240 // Drivers should use this API if they wish to request a level higher than the previous level they required
241 // Drivers should keep track of the level they require and be disciplined
244 __PM_ASSERT(aLevel<Levels[aRequester]);
245 Levels[aRequester]=aLevel;
246 if(aLevel > iCurrentLevel) // need to increase the level
248 // if(aLevel <= MAXLEVEL)
249 // aLevel = MAXLEVEL;
250 iCurrentLevel = aLevel;
251 iCurrentLevelOwnerId = aRequester;
255 // Modify hardware register bits to set the level of the resource to aLevel
260 // If the resource is asynchronous may need to sleep or block the thread until the change is complete
267 void SharedMultilevelResource1::ReduceToLevel(TUint aLevel, TInt aRequester)
270 // Drivers should use this API if they wish to request a level higher than the previous level they required
273 __PM_ASSERT(aLevel>Levels[aRequester]);
275 Levels[aRequester]=aLevel;
276 if(aLevel < iCurrentLevel && aRequester == iCurrentLevelOwnerId) // the holder of the current level as lowered its request
278 FindMaxLevel(&iCurrentLevel, &iCurrentLevelOwnerId); // find max level required and the ID of its holder
282 // Modify hardware register bits to set the level of the resource to iCurrentLevel
287 // If the resource is asynchronous may need to sleep or block the thread until the change is complete
294 TUint SharedMultilevelResource1::GetResourceLevel()
296 return iCurrentLevel;
299 void SharedMultilevelResource1::FindMaxLevel(TUint* aLevel, TInt* aId)
304 // Place your clever array search algorithm here...
305 // return max level and id of owner
308 TInt BinaryPowerInit(); // the Symbian example Battery Monitor and Power HAL handling
310 GLDEF_C TInt KernelModuleEntry(TInt aReason)
312 if(aReason==KModuleEntryReasonVariantInit0)
317 // Start the Resource Manager earlier so that Variant and other extension could make use of Power Resources
319 __KTRACE_OPT(KPOWER, Kern::Printf("Starting Template Resource controller"));
320 new(&TheResourceManager)TemplateResourceManager;
321 TheResourceManager.InitResources();
324 else if(aReason==KModuleEntryReasonExtensionInit0)
326 __KTRACE_OPT(KPOWER, Kern::Printf("Starting Template power controller"));
330 // Start the Kernel-side Battery Monitor and hook a Power HAL handling function.
331 // Symbian provides example code for both of the above in \e32\include\driver\binpower.h
332 // You may want to write your own versions.
333 // The call below starts the example Battery Monitor and hooks the example Power HAL handling function
334 // At the end we return an error to make sure that the entry point is not called again with
335 // KModuleEntryReasonExtensionInit1 (which would call the constructor of TheResourceManager again)
337 TInt r = BinaryPowerInit();
339 __PM_PANIC("Can't initialise Binary Power model");
340 DTemplatePowerController* c = new DTemplatePowerController();
344 __PM_PANIC("Can't create Power Controller");
346 else if(aReason==KModuleEntryReasonExtensionInit1)
348 // does not get called...