⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oemidle.c

📁 PXA27X_CAYMAN BSP from CAYMAN board
💻 C
字号:
/* Copyright ?2002 Intel Corp.  */
/*++

Module Name:  $Workfile: OEMIdle.c $

Abstract:  
 Intel XScale Microarchitecture OEM Idle routine

Notes:

--*/

#include <windows.h>
#include <math.h>
#include <stdlib.h>
#include <bldver.h>
#include <nkintr.h>
#include "bvd1.h"
#include "bvd1bd.h"
#include "timer.h"
#include "pmu.h"
#include "drv_glob.h"


extern CPUEnterIdle();
extern void SetCoreVoltage(DWORD dacValue);
extern XSC1ReadCLKCFG(void);
extern void XSC1EnterTurbo(void);
extern void XSC1ExitTurbo(void);
extern DWORD curridlehigh, curridlelow; // 64-bit idle time in ms
extern DWORD CurMSec;  
extern BOOL bProfileTimerRunning;
extern BOOL fIntrTime;
extern void SetCoreFrequency(int LMult, int NMult, int run_mode_flag, int fastbus_mode_flag);
extern DWORD dwReschedTime; 
static DWORD dwPartialCurMSec = 0;  // Keep sub-millisecond leftover.
volatile ULARGE_INTEGER CurTicks = { 0, 0 };

//
//  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. 
//
void OEMIdle (DWORD dwIdleParam) 
{
    DWORD dwIdleMSec, dwIdleTick, dwTicksElapsed;
    DWORD dwPrevMSec = CurMSec;
    DWORD idletime;
	DWORD dwCount;
    div_t div_result;
    static int sample_counter;
	static int actual_idle_index;
    static int actual_idle;
    static int predict_total_idle;
    static int IDLE_State; 
	static int  IDLE_State_var; 
	static int idle_counter,prev_util;
    static int systemalive, total_idletime;
    static int idle_percentage;
    unsigned long  CLKCFGValue = 0;
    int i =0, IDLE_FLAG=0;
	int util = 0;
    int TOUCH_FLAG = 0;
#ifdef USING_DVM
    unsigned int  InterestingInterrupts;
#endif
    static int NUM_CONTINUE_TOUCH;

    ULARGE_INTEGER currIdle = 
    {
        curridlelow,
        curridlehigh
    };

    volatile PDRIVER_GLOBALS v_pDriverGlobals = (volatile PDRIVER_GLOBALS)DRIVER_GLOBALS_U_VIRTUAL;	
   	volatile XLLP_CLKMGR_T   *v_pClkReg = (volatile XLLP_CLKMGR_T *)CLK_BASE_U_VIRTUAL;
    volatile XLLP_OST_T *v_pOSTReg = (volatile XLLP_OST_T *)OST_BASE_U_VIRTUAL;
    volatile XLLP_INTC_T  *v_pICReg = (volatile XLLP_INTC_T *)INTC_BASE_U_VIRTUAL;
	//
    // Check to see if scheduler needs to run before 
    // entering "idle"
    //

    //
    // Dougfir (Talisker) or later
    //
    //return;
    //
    // Calculate number MS until next scheduled event 
    //
    if ((int) (dwIdleMSec = dwReschedTime - dwPrevMSec) <= 0)
    {
        //
        // Already time to wake up - return to scheduler
        //
        return;
    }

    if (bPMURunning)
    {
        //
        // If PMU is currently sampling, we can't enter idle mode,
        // else the PMU counters will be turned off
        //
        return;
    }


    if (bProfileTimerRunning) 
    {
        // system timer is running at CPU specific profiling value - just call CPUEnterIdle and return
        CPUEnterIdle();
        return;
    }

#ifdef USING_DVM
    CLKCFGValue = XSC1ReadCLKCFG();
    if(IDLE_State == 1)
    {    	    
        if( CLKCFGValue ==1 || CLKCFGValue ==3 )
    	{
            XSC1ExitTurbo();
            SetCoreVoltage(200);           
    	}
    }
    else if (  IDLE_State == 0 && (dwIdleMSec * idle_percentage) > 2000)   
    {    		
	    if( CLKCFGValue ==1 || CLKCFGValue ==3 )
		{
            XSC1ExitTurbo();
            SetCoreVoltage(200);	       
		}
    }
#endif
	
    //
    // Check if we're profiling, or doing interrupt latency timing  
    //
    if (bProfileTimerRunning || fIntrTime)
    {
        // idle till end of tick
        CPUEnterIdle();


        // Update global idle time and return
        currIdle.QuadPart  += RESCHED_PERIOD;
        curridlelow = currIdle.LowPart;
        curridlehigh = currIdle.HighPart;

        EdbgOutputDebugString("exit 4\r\n");
        return;
    }
 
	//
    // Calculate ticks that have elapsed since last timer firing
    //
    dwCount = PerfCountSinceTick();

    //
    // Add any partial Msec from last time
    //
    dwCount += dwPartialCurMSec;

    //
    // Calculate new Partial Msec
    //
    dwPartialCurMSec = dwCount % OEM_TICKS_1MS;

    //
    // Convert to MS and add to CurMsec
    //
    dwCount /= OEM_TICKS_1MS;
    CurMSec += dwCount;

    //
    // Adjust idle with any Msecs that have elapsed 
    // (due to dwPartialCurMSec tracking) and...
    //
    // Only idle if there is more than a Msec to do so	
    if ((int) (dwIdleMSec -= CurMSec - dwPrevMSec) > 0)
    {
        //
        // Adjust PreviousMsec to Current 
        //
        //NKDbgPrintfW(TEXT("Will be enter idle state\r\n"));

        dwPrevMSec = CurMSec;

        //
        // Check idle time to timer's max timeout value
        //
        if (dwIdleMSec > MAX_IDLE_TIME)
        {
            dwIdleMSec = MAX_IDLE_TIME;
        }
        
        dwIdleTick = dwIdleMSec * OEM_TICKS_1MS;

        //
        // Set match timer to length of time for idlemode
        //   
        v_pOSTReg->osmr0 = v_pOSTReg->oscr0 + dwIdleTick;

        //Clear and enable the M0 interrupt
		TIMER_M0_INT_CLR(v_pOSTReg->ossr);      
        TIMER_M0_INT_EN(v_pOSTReg->oier);

        
		// Set CPU to Idle to be awakened on any interrupt
		//
		//  activetime = CurMSec - firstidle;

		CPUEnterIdle();

		INTERRUPTS_OFF();

#ifdef USING_DVM
    	if ( (v_pICReg->icmr & v_pICReg->icip) != 0x04000000)
		{
		    IDLE_State_var +=0;
			IDLE_FLAG = 0;		
		}		
		else
		{
	        
		    IDLE_State_var +=1; 
			IDLE_FLAG = 1;		
		}
#endif
			
        //      
        //  We've been interrupted from our idle time:
        //     * Update counters and idle time
        //     * Re-arm (&clear) system timer interval and return
        //
        
        //
        // We're awake! 
        // The wake-up ISR (or any other ISR) has already run.
        //
        if (dwPrevMSec != CurMSec) 
        {
            //
            // We completed the full period we asked to sleep.  Update the counters.
            //
            CurMSec  += (dwIdleMSec - RESCHED_PERIOD); // Subtract resched period, because ISR also incremented.
            CurTicks.QuadPart += (dwIdleMSec - RESCHED_PERIOD) * OEM_TICKS_1MS;

            currIdle.QuadPart += dwIdleMSec;
		

        }
        else 
        {
            //
            // Some other interrupt woke us up before the 
            // full idle period was complete.  
			//

			//
			// Determine how much time has elapsed and update time variables.
            //
			// Note: If oscr went past the match point, the math still works since
			// it accounts for the dwIdleTick time plus the time past the match.
			// 
			dwTicksElapsed = dwIdleTick - ((DWORD)v_pOSTReg->osmr0 - (DWORD)v_pOSTReg->oscr0);

            CurTicks.QuadPart += dwTicksElapsed;
            currIdle.QuadPart += (dwTicksElapsed/OEM_TICKS_1MS);

            //
            // Calculate new Partial Msec
            //
			dwCount = dwPartialCurMSec;
            dwCount += dwTicksElapsed;
			dwPartialCurMSec = dwCount % OEM_TICKS_1MS;

            //
            // Convert to MS and add to CurMsec
            //
			div_result = div (dwCount, OEM_TICKS_1MS);
			dwCount = div_result.quot;
            CurMSec += dwCount;
        }
        
		//
		// Update idle time variables
		//
		curridlelow = currIdle.LowPart;
		curridlehigh = currIdle.HighPart;
        idletime = dwTicksElapsed/OEM_TICKS_1MS;
       
        v_pDriverGlobals->uninit_misc.idletime += (unsigned char)idletime;
        //
        // Restore timer increment to normal value
        //
	    v_pOSTReg->osmr0 = v_pOSTReg->oscr0 + RESCHED_INCREMENT;
        
        //Clear and enable the interrupt
		TIMER_M0_INT_CLR(v_pOSTReg->ossr);      
        TIMER_M0_INT_EN(v_pOSTReg->oier);
		//enable the interrupt for DVM

		//
		// Caller will turn interrupts back on
		//

    }  
	else
	{
       idletime = 0;
	   
#ifdef USING_DVM
	   IDLE_State_var =IDLE_State_var + 1;
       IDLE_FLAG = 1;
#endif
	   
	}

#ifdef USING_DVM
	if(sample_counter <=5)
	{
		sample_counter++;
        predict_total_idle += dwIdleMSec;
        actual_idle += idletime;				
	}

	if(sample_counter ==5)
	{
		idle_percentage = (100* actual_idle/ predict_total_idle);
		sample_counter = 0;
        actual_idle = 0;
        predict_total_idle = 0;
		if(IDLE_State_var >= 5)
            IDLE_State  = 1;
	    else
		    IDLE_State = 0;
		IDLE_State_var = 0;
    }

    CLKCFGValue = XSC1ReadCLKCFG();

    if(IDLE_State == 0)
    {  
  	   if( CLKCFGValue ==0 || CLKCFGValue ==2 )
		{
			VM_SetVoltage(0);
			XSC1EnterTurbo();	    
		}
    }
#endif
	
    return;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -