📄 idle.c
字号:
//**********************************************************************
//
// Filename: idle.c
//
// Description:
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Use of this source code is subject to the terms of the Cirrus end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to
// use this source code. For a copy of the EULA, please see the
// EULA.RTF on your install media.
//
// Copyright(c) Cirrus Logic Corporation 2005, All Rights Reserved
//
//**********************************************************************
#include <windows.h>
#include <bldver.h>
#include <nkintr.h>
#include <oalintr.h>
#include <clocks.h>
#include <hwdefs.h>
//
// Kernel global variables used by GetIdleTime( ) to determine CPU utilization
//
extern DWORD idleconv; // translation constant in 1 ms units
extern DWORD curridlehigh, curridlelow; // 64-bit idle time in ms
extern void EnterStandbyMode();
// dougfir or later
//
extern volatile DWORD CurMSec;
extern DWORD dwReschedTime;
extern BOOL fIntrTime;
extern BOOL bProfileTimerRunning;
volatile ULARGE_INTEGER CurTicks = { 0, 0 };
extern DWORD dwReschedIncrement;
//extern DWORD OEMCount1ms;
extern ULONG gulCS8950KitlUsed;
extern volatile DWORD gdwInterruptMask1, gdwInterruptMask2;
extern volatile DWORD gdwInterruptWakeMask1, gdwInterruptWakeMask2;
extern volatile BYTE gfSysIntrWakeupMask[SYSINTR_MAXIMUM];
extern volatile DWORD gdwLastWakeupSource;
extern volatile BOOL gfResumeFlag;
extern volatile DWORD dwTimeValueWhenSuspend;
//
// CPU-specific functions for OEMIdle
//
extern void CPUEnterIdle(DWORD dwIdleParam);
extern DWORD PerfCountSinceTick();
extern BOOL SysIntrNumToInterruptMask
(
DWORD dwSysIntr,
PULONG pulInterruptMask1,
PULONG pulInterruptMask2
);
//------------------------------------------------------------------------------
//
// This routine is called by the kernel when there are no threads ready to
// run. The CPU should be put into a reduced power mode and halted. It is
// important to be able to resume execution quickly upon receiving an interrupt.
// Note: It is assumed that interrupts are off when OEMIdle is called. Interrrupts
// are turned off when OEMIdle returns.
//
//------------------------------------------------------------------------------
VOID OEMIdle(DWORD idleParam)
{
UINT32 baseMSec ;
ULARGE_INTEGER idle;
UINT32 idleMSec;
INT32 usedCounts, idleCounts;
// Get current system timer counter
baseMSec = CurMSec;
idleMSec = dwReschedTime - baseMSec;
// Idle time has expired - we need to return
if ((INT32)idleMSec <= 0) return;
// Find how many hi-res ticks was already used
usedCounts = PerfCountSinceTick();
/* usedMSec=usedCounts/OEM_COUNT_1MS;
if ( idleMSec + usedMSec > IDLE_MAX_MS)
{
idleMSec=IDLE_MAX_MS-usedMSec;
}*/
// We should wait this time
idleCounts = OEM_COUNT_1MS * idleMSec;
// Move SoC/CPU to idle mode
CPUEnterIdle( 0 );
if ((int)(CurMSec - dwReschedTime) < 0 ) {
idleCounts = PerfCountSinceTick();
}
// Get real idle value. If result is negative we didn't idle at all.
idleCounts -= usedCounts;
if (idleCounts < 0) idleCounts = 0;
// Update idle counters
idle.LowPart = curridlelow;
idle.HighPart = curridlehigh;
idle.QuadPart += idleCounts/OEM_COUNT_1MS;
curridlelow = idle.LowPart;
curridlehigh = idle.HighPart;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//
// SC_GetTickCount must take into account the partials to reflect where we really
// are in time AND IT SHOULD NOT MODIFY ANY OF THE GLOBALS.
//
DWORD SC_GetTickCount(void)
{
DWORD dwCount;
dwCount=(DWORD)(CurTicks.QuadPart/983);
CurMSec=dwCount;
return dwCount;
/*
#if (RESCHED_PERIOD==1)
// RETAILMSG(1,(L"SC_COUNT %d\r\n",CurMSec));
return CurMSec;
#else
UINT32 count;
INT32 offset;
// System timer tick period exceeds 1 ms.
//
// This code adjusts the accuracy of the returned value to the nearest
// MSec when the system tick exceeds 1 ms. The following code checks if
// a system timer interrupt occurred between reading the CurMSec value
// and the call to fetch the HiResTicksSinceSysTick. If so, the value of
// CurMSec and Offset is re-read, with the certainty that a system timer
// interrupt will not occur again.
do {
count = CurMSec;
offset = PerfCountSinceTick();
}
while (count != CurMSec);
// Adjust the MSec value with the contribution from HiRes counter.
count += offset/OEM_COUNT_1MS;
return count;
#endif
*/
}
//****************************************************************************
// OEMPowerOff
//****************************************************************************
// Power management stuff.
//
//
VOID OEMPowerOff(void)
{
// volatile ULONG ulTemp;
ULONG ulCscPwrCnt, ulCscDevCfg;
//
// Print out the current clock rates to the debug port.
//
NKDbgPrintfW( L"OEMPowerOff\r\n" );
INTERRUPTS_OFF();
//
// Replace the interrupt mask with the wake event interrupt mask. These
// will be the only interrupts that can wake us from suspend.
//
*VIC1_INTCLEAR = 0xFFFFFFFF;
*VIC2_INTCLEAR = 0xFFFFFFFF;
*VIC1_INTENABLE = gdwInterruptWakeMask1 | INT1_TIMER1;
*VIC2_INTENABLE = gdwInterruptWakeMask2;
//
// Check to see if there is a kitl connection. If so then
// keep the clocks on.
//
if(!gulCS8950KitlUsed)
{
//
// Power down the system clocks here.
//
ulCscPwrCnt = *CSC_PWRCNT;
ulCscDevCfg = *CSC_DEVCFG;
//
// Power down the clocks as much as possible.
//
*CSC_SYSLOCK = 0xAA;
*CSC_PWRCNT = 0;
*CSC_SYSLOCK = 0xAA;
*CSC_DEVCFG = (ulCscDevCfg &
~(DEVCFG_KEYS | DEVCFG_ADCPD | DEVCFG_RAS |
DEVCFG_TIN | DEVCFG_U1EN | DEVCFG_U2EN |
DEVCFG_U3EN)) | DEVCFG_SHENA;
*CSC_SYSLOCK = 0xAA;
*CSC_CLKSET2 = CLKSET2_VALUE & ~( CLKSET2_PLL2_EN | CLKSET2_PLL2_NBYP);
*SDRAM_REFRESH = SDRAM_14MHZ_REFRESH_VALUE;
*CSC_SYSLOCK = 0xAA;
*CSC_CLKSET1 = CLKSET1_VALUE & ~CLKSET1_PLL1_NBYP;
//
// Flush the pipeline.
//
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
}
gfResumeFlag = FALSE;
INTERRUPTS_ON();
dwTimeValueWhenSuspend= *RTC_DR;// *TIM_DEBUGVALUELOW;
while(!gfResumeFlag)
{
if(gulCS8950KitlUsed)
{
CPUEnterIdle(0);
}
else
{
EnterStandbyMode( );
//ulTemp = *CSC_STBY;
}
}
INTERRUPTS_OFF();
//
// Check to see if there is a kitl connection. If so then
// keep the clocks on.
//
if(!gulCS8950KitlUsed)
{
//
// Power down the system clocks here.
//
*CSC_SYSLOCK = 0xAA;
*CSC_CLKSET1 = CLKSET1_VALUE;
//
// Flush the pipeline.
//
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
__emit(0xe1a00000);
*SDRAM_REFRESH = SDRAM_REFRESH_VALUE;
*CSC_SYSLOCK = 0xAA;
*CSC_CLKSET2 = CLKSET2_VALUE;
*CSC_SYSLOCK = 0xAA;
*CSC_DEVCFG = ulCscDevCfg;
*CSC_SYSLOCK = 0xAA;
*CSC_PWRCNT = ulCscPwrCnt;
}
//
// Restore the original interupt mask.
//
*VIC1_INTCLEAR = 0xFFFFFFFF;
*VIC2_INTCLEAR = 0xFFFFFFFF;
*VIC1_INTENABLE = gdwInterruptMask1 | INT1_TIMER1;
*VIC2_INTENABLE = gdwInterruptMask2;
INTERRUPTS_ON();
}
//****************************************************************************
// OEMPowerManagerInit
//****************************************************************************
// Power Managment Initialization routine.
//
//
DWORD OEMPowerManagerInit(void)
{
int ulInt;
for(ulInt = 0; ulInt < SYSINTR_MAXIMUM ; ulInt++)
{
gfSysIntrWakeupMask[ ulInt ] = 0;
}
//
// Clear the interrupt wake mask
//
gdwInterruptWakeMask1 = 0 ;
gdwInterruptWakeMask2 = 0 ;
return 1;
}
//****************************************************************************
// OEMSetWakeupSource
//****************************************************************************
// This sets the source for the wakeup interrupt.
//
//
DWORD OEMSetWakeupSource( DWORD dwSources)
{
DWORD dwIntMask1, dwIntMask2;
NKDbgPrintfW( L"OEMSetWakeupSource dwSource = 0x%x\r\n",dwSources );
if(dwSources <SYSINTR_MAXIMUM)
{
//
// OEMTranslateSysIntr currently returns the passed value.
//
// DWORD dwPhysInt = OEMTranslateSysIntr(dwSources);
gfSysIntrWakeupMask[dwSources] = 1;
SysIntrNumToInterruptMask(dwSources, &dwIntMask1, &dwIntMask2);
gdwInterruptWakeMask1 |= dwIntMask1;
gdwInterruptWakeMask2 |= dwIntMask2;
return 1;
}
return 0;
}
//****************************************************************************
// OEMResetWakeupSource
//****************************************************************************
// This clears the specified wakeup interrupt.
//
//
DWORD OEMResetWakeupSource( DWORD dwSources)
{
DWORD dwIntMask1, dwIntMask2;
NKDbgPrintfW( L"OEMResetWakeupSource dwSource = 0x%x\r\n",dwSources );
if(dwSources < SYSINTR_MAXIMUM)
{
//
// OEMTranslateSysIntr just returns the passed value.
//
//DWORD physInt = OEMTranslateSysIntr(dwSources);
gfSysIntrWakeupMask[dwSources] = 0;
SysIntrNumToInterruptMask(dwSources, &dwIntMask1, &dwIntMask2);
gdwInterruptWakeMask1 &= ~dwIntMask1;
gdwInterruptWakeMask2 &= ~dwIntMask2;
return 1;
}
return 0;
}
//****************************************************************************
// OEMClearIntSources
//****************************************************************************
// I am going to assume there is only one interrupt in the queue
// when the system wakes up from an interrupt.
//
//
void OEMClearIntSources( )
{
NKDbgPrintfW( L"OEMClearIntSources.\r\n");
gfResumeFlag = FALSE;
}
//****************************************************************************
// OEMGetWakeupSource
//****************************************************************************
// Gets the last interrupt that woke up the system.
//
//
DWORD OEMGetWakeupSource(void)
{
NKDbgPrintfW( L"OEMGetWakeupSource.\r\n");
return gdwLastWakeupSource;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -