1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/specific/power.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,351 @@
1.4 +// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// template\template_variant\specific\power.cpp
1.18 +// Template Power Management
1.19 +// (see also variant.cpp for a discussion on Sleep modes and xyin.cpp for example
1.20 +// of usage of Resource Manager and Peripheral self power down and interaction
1.21 +// with Power Controller for Wakeup Events)
1.22 +//
1.23 +//
1.24 +
1.25 +#include "template_power.h"
1.26 +
1.27 +static TemplateResourceManager TheResourceManager;
1.28 +
1.29 +DTemplatePowerController* TTemplatePowerController::iPowerController;
1.30 +
1.31 +
1.32 +//-/-/-/-/-/-/-/-/-/ class DTemplatePowerController /-/-/-/-/-/-/-/-/-/
1.33 +
1.34 +DTemplatePowerController::DTemplatePowerController()
1.35 + {
1.36 + Register(); // register Power Controller with Power Manager
1.37 + TTemplatePowerController::RegisterPowerController(this);
1.38 + }
1.39 +
1.40 +void DTemplatePowerController::CpuIdle()
1.41 + {
1.42 + Arch::TheAsic()->Idle();
1.43 + }
1.44 +
1.45 +void DTemplatePowerController::EnableWakeupEvents()
1.46 + {
1.47 + //
1.48 + // TO DO: (mandatory)
1.49 + //
1.50 + // Enable tracking of wake-up events directly in hardware. If the hardware is controlled by a Driver
1.51 + // or Extension, may need to disable interrupts and preemption around the code that accesses the hardware
1.52 + // and set up a flag which the Driver/Extension code need to read before modifying the state of that piece
1.53 + // of hardware. Note in that case the Driver/Extension may need to link to this Library.
1.54 + //
1.55 +
1.56 + //
1.57 + // EXAMPLE ONLY
1.58 + // In this example we simply assume that the driver will call the Power Controller every time a
1.59 + // wakeup event occurr. It is up to the Power Controller to know if it is tracking them or not.
1.60 + // We also assume that if a wakeup event occurrs when the CPU is in Standby, this will automatically
1.61 + // bring it back from that state.
1.62 + iWakeupEventsOn = ETrue; // start tracking wakeup events
1.63 + }
1.64 +
1.65 +void DTemplatePowerController::DisableWakeupEvents()
1.66 + {
1.67 + //
1.68 + // TO DO: (mandatory)
1.69 + //
1.70 + // Disable tracking of wake-up events directly in hardware or if the hardware is controlled by a Driver or
1.71 + // Extension need to set up a flag which the Driver/Extension reads whenever the event occurs, in order to
1.72 + // find out if it needs to deliver notification to the Power Controller
1.73 + //
1.74 + iWakeupEventsOn = EFalse; // stop tracking wakeup events
1.75 + }
1.76 +
1.77 +void DTemplatePowerController::AbsoluteTimerExpired()
1.78 + {
1.79 + if (iTargetState == EPwStandby && iWakeupEventsOn)
1.80 + {
1.81 + iWakeupEventsOn = EFalse; // one occurred, no longer track wakeup events
1.82 + WakeupEvent();
1.83 + }
1.84 + }
1.85 +
1.86 +void DTemplatePowerController::PowerDown(TTimeK aWakeupST)
1.87 + {
1.88 + if (iTargetState == EPwStandby)
1.89 + {
1.90 + //
1.91 + // TO DO: (mandatory)
1.92 + //
1.93 + // Converts between the Wakeup time in System Time units as passed in to this function and a Wakeup
1.94 + // time in RTC units. The following code is given as an example how to convert between System time units
1.95 + // RTC time units on a system with a 32 bit RTC timer and which is incremented on a second interval:
1.96 + //
1.97 + TUint32 wakeupRTC;
1.98 + if (aWakeupST)
1.99 + {
1.100 + TUint32 nowRTC = TTemplate::RtcData();
1.101 + TTimeK nowST = Kern::SystemTime();
1.102 + __KTRACE_OPT(KPOWER,Kern::Printf("system time: now = 0x%lx(us) wakeup = 0x%lx(us)", nowST, aWakeupST));
1.103 + if (aWakeupST < nowST)
1.104 + return;
1.105 + Int64 deltaSecs = (aWakeupST - nowST) / 1000000;
1.106 + if (deltaSecs <= 0)
1.107 + return;
1.108 + if (deltaSecs + (Int64)nowRTC > (Int64)(KMaxTInt - 2))
1.109 + wakeupRTC = (KMaxTInt - 2); // RTC can't wrap around during standby
1.110 + else
1.111 + wakeupRTC = nowRTC + deltaSecs;
1.112 + __KTRACE_OPT(KPOWER,Kern::Printf("RTC: now = %d(s) wakeup = %d(s)", nowRTC, wakeupRTC));
1.113 + }
1.114 + else
1.115 + wakeupRTC = 0;
1.116 + //
1.117 + // TO DO: (optional)
1.118 + //
1.119 + // It then uses the calculated value to program the RTC to wakeup the System at the Wakeup
1.120 + // time ans sets the CPU and remaining hardware to go to the correponding low power mode. When the
1.121 + // state of the Core and Core Peripherals is not preserved in this mode the following is usually
1.122 + // required:
1.123 + // - save current Core state (current Mode, banked registers for each Mode and Stack Pointer for
1.124 + // both current and User Modes
1.125 + // - save MMU state: Control Register, TTB and Domain Access Control
1.126 + // - Flush Dta Cache and drain Write Buffer
1.127 + // - save Core Peripherals state: Interrupt Controller, Pin Function, Bus State and Clock settings
1.128 + // SDRAM should be put in self refresh mode. Peripheral devices involved in detection of Wakeup events
1.129 + // should be left powered.
1.130 + // The Tick timer should be disabled and the current count of this and other System timers shall be
1.131 + // saved.
1.132 + // On wakeing up the state should be restored from the save state as above. SDRAM shall be brought back
1.133 + // under CPU control, The Tick count shall be restored and timers re-enabled.
1.134 +
1.135 + // We assume that if a wakeup event occurrs when the CPU is in Standby, this will automatically
1.136 + // bring it back from that state. Therefore we stop tracking wakeup events as the Power Manager will
1.137 + // complete any pending notifications anyway. When the driver delivers its notification, we just ignore
1.138 + // it.
1.139 + iWakeupEventsOn = EFalse; // tracking of wakeup events is now done in hardware
1.140 + }
1.141 + else
1.142 + {
1.143 + Kern::Restart(0x80000000);
1.144 + }
1.145 + }
1.146 +
1.147 +//-/-/-/-/-/-/-/-/-/ class TTemplatePowerController /-/-/-/-/-/-/-/-/-/
1.148 +
1.149 +EXPORT_C TemplateResourceManager* TTemplatePowerController::ResourceManager()
1.150 + {
1.151 + return &TheResourceManager;
1.152 + }
1.153 +
1.154 +
1.155 +EXPORT_C void TTemplatePowerController::WakeupEvent()
1.156 + {
1.157 + if(!iPowerController)
1.158 + __PM_PANIC("Power Controller not present");
1.159 + else if(iPowerController->iWakeupEventsOn)
1.160 + {
1.161 + iPowerController->iWakeupEventsOn=EFalse; // one occurred, no longer track wakeup events
1.162 + iPowerController->WakeupEvent();
1.163 + }
1.164 + }
1.165 +
1.166 +//-/-/-/-/-/-/-/-/-/ class TemplateResourceManager /-/-/-/-/-/-/-/-/-/
1.167 +
1.168 +void TemplateResourceManager::InitResources()
1.169 + {
1.170 + //
1.171 + // TO DO: (optional)
1.172 + //
1.173 + // Initialise any power resources required by the platform and not initialised in the Bootstrap
1.174 + //
1.175 + }
1.176 +
1.177 +//-/-/-/-/-/-/-/-/-/ interface for shared resources /-/-/-/-/-/-/-/-/-/
1.178 +
1.179 +void SharedBinaryResource1::Use()
1.180 + {
1.181 + NKern::Lock(); // lock Kernel as shared resource is likely to be modified from different threads
1.182 + if (iCount++ == 0)
1.183 + {
1.184 + //
1.185 + // TO DO: (optional)
1.186 + //
1.187 + // Modify hardware register bit or bits to switch the resource On. If the resource
1.188 + // can be accessed from an ISR need to disable/enable interrupts around it.
1.189 + //
1.190 + NKern::Unlock();
1.191 + //
1.192 + // TO DO: (optional)
1.193 + //
1.194 + // If the resource is asynchronous may need to sleep or block the thread until the change is complete
1.195 + //
1.196 + }
1.197 + else
1.198 + NKern::Unlock();
1.199 + }
1.200 +
1.201 +void SharedBinaryResource1::Release()
1.202 + {
1.203 + NKern::Lock();
1.204 + __PM_ASSERT(iCount);
1.205 + if (--iCount == 0)
1.206 + {
1.207 + //
1.208 + // TO DO: (optional)
1.209 + //
1.210 + // Modify hardware register bit or bits to switch the resource Off. If the resource
1.211 + // can be accessed from an ISR need to disable/enable interrupts around it.
1.212 + //
1.213 + NKern::Unlock();
1.214 + //
1.215 + // TO DO: (optional)
1.216 + //
1.217 + // If the resource is asynchronous may need to sleep or block the thread until the change is complete
1.218 + //
1.219 + }
1.220 + else
1.221 + NKern::Unlock();
1.222 + }
1.223 +
1.224 +TUint SharedBinaryResource1::GetCount()
1.225 + {
1.226 + return iCount;
1.227 + }
1.228 +
1.229 +SharedMultilevelResource1::SharedMultilevelResource1()
1.230 + //
1.231 + // TO DO: (optional)
1.232 + //
1.233 + // May need to initialise current level and the Id of its owner if these have been initialised in the Bootstrap
1.234 + //
1.235 + // : iCurrentLevel(/* a level for this resource as initialised in the Bootstrap */),
1.236 + // iCurrentLevelOwnerId(/* the Id of the requester of this resource that requires the initial value */)
1.237 + {
1.238 + }
1.239 +
1.240 +void SharedMultilevelResource1::IncreaseToLevel(TUint aLevel, TInt aRequester)
1.241 + {
1.242 + //
1.243 + // Drivers should use this API if they wish to request a level higher than the previous level they required
1.244 + // Drivers should keep track of the level they require and be disciplined
1.245 + //
1.246 + NKern::Lock();
1.247 + __PM_ASSERT(aLevel<Levels[aRequester]);
1.248 + Levels[aRequester]=aLevel;
1.249 + if(aLevel > iCurrentLevel) // need to increase the level
1.250 + {
1.251 + // if(aLevel <= MAXLEVEL)
1.252 + // aLevel = MAXLEVEL;
1.253 + iCurrentLevel = aLevel;
1.254 + iCurrentLevelOwnerId = aRequester;
1.255 + //
1.256 + // TO DO: (optional)
1.257 + //
1.258 + // Modify hardware register bits to set the level of the resource to aLevel
1.259 + NKern::Unlock();
1.260 + //
1.261 + // TO DO: (optional)
1.262 + //
1.263 + // If the resource is asynchronous may need to sleep or block the thread until the change is complete
1.264 + //
1.265 + }
1.266 + else
1.267 + NKern::Unlock();
1.268 + }
1.269 +
1.270 +void SharedMultilevelResource1::ReduceToLevel(TUint aLevel, TInt aRequester)
1.271 + {
1.272 + //
1.273 + // Drivers should use this API if they wish to request a level higher than the previous level they required
1.274 + //
1.275 + NKern::Lock();
1.276 + __PM_ASSERT(aLevel>Levels[aRequester]);
1.277 +
1.278 + Levels[aRequester]=aLevel;
1.279 + if(aLevel < iCurrentLevel && aRequester == iCurrentLevelOwnerId) // the holder of the current level as lowered its request
1.280 + {
1.281 + FindMaxLevel(&iCurrentLevel, &iCurrentLevelOwnerId); // find max level required and the ID of its holder
1.282 + //
1.283 + // TO DO: (optional)
1.284 + //
1.285 + // Modify hardware register bits to set the level of the resource to iCurrentLevel
1.286 + NKern::Unlock();
1.287 + //
1.288 + // TO DO: (optional)
1.289 + //
1.290 + // If the resource is asynchronous may need to sleep or block the thread until the change is complete
1.291 + //
1.292 + }
1.293 + else
1.294 + NKern::Unlock();
1.295 + }
1.296 +
1.297 +TUint SharedMultilevelResource1::GetResourceLevel()
1.298 + {
1.299 + return iCurrentLevel;
1.300 + }
1.301 +
1.302 +void SharedMultilevelResource1::FindMaxLevel(TUint* aLevel, TInt* aId)
1.303 + {
1.304 + //
1.305 + // TO DO: (optional)
1.306 + //
1.307 + // Place your clever array search algorithm here...
1.308 + // return max level and id of owner
1.309 + }
1.310 +
1.311 +TInt BinaryPowerInit(); // the Symbian example Battery Monitor and Power HAL handling
1.312 +
1.313 +GLDEF_C TInt KernelModuleEntry(TInt aReason)
1.314 + {
1.315 + if(aReason==KModuleEntryReasonVariantInit0)
1.316 + {
1.317 + //
1.318 + // TO DO: (optional)
1.319 + //
1.320 + // Start the Resource Manager earlier so that Variant and other extension could make use of Power Resources
1.321 + //
1.322 + __KTRACE_OPT(KPOWER, Kern::Printf("Starting Template Resource controller"));
1.323 + new(&TheResourceManager)TemplateResourceManager;
1.324 + TheResourceManager.InitResources();
1.325 + return KErrNone;
1.326 + }
1.327 + else if(aReason==KModuleEntryReasonExtensionInit0)
1.328 + {
1.329 + __KTRACE_OPT(KPOWER, Kern::Printf("Starting Template power controller"));
1.330 + //
1.331 + // TO DO: (optional)
1.332 + //
1.333 + // Start the Kernel-side Battery Monitor and hook a Power HAL handling function.
1.334 + // Symbian provides example code for both of the above in \e32\include\driver\binpower.h
1.335 + // You may want to write your own versions.
1.336 + // The call below starts the example Battery Monitor and hooks the example Power HAL handling function
1.337 + // At the end we return an error to make sure that the entry point is not called again with
1.338 + // KModuleEntryReasonExtensionInit1 (which would call the constructor of TheResourceManager again)
1.339 + //
1.340 + TInt r = BinaryPowerInit();
1.341 + if (r!= KErrNone)
1.342 + __PM_PANIC("Can't initialise Binary Power model");
1.343 + DTemplatePowerController* c = new DTemplatePowerController();
1.344 + if(c)
1.345 + return KErrGeneral;
1.346 + else
1.347 + __PM_PANIC("Can't create Power Controller");
1.348 + }
1.349 + else if(aReason==KModuleEntryReasonExtensionInit1)
1.350 + {
1.351 + // does not get called...
1.352 + }
1.353 + return KErrArgument;
1.354 + }