os/kernelhwsrv/bsptemplate/asspandvariant/template_variant/specific/power.cpp
changeset 0 bde4ae8d615e
     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 +	}