//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft 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 LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  Module: timer.c
//
//  Interface to OAL timer services.
//  !! Caution: If serial message for debugging is in timer function(OEMIdle() or OALTimerIntrHandler() etc.),
//              System timer tick can be generated by some error.
//              So, Must avoiding to insert message for debug in function related timer.


#include <windows.h>

#include <oal.h>
#include "soc_cfg.h"
#include "base_regs.h"
#include "register_map.h"
#include "bsp_gpio.h"
#include "bsp_args.h"
#include "image_cfg.h"

#include <pmplatform.h>
#include <dvfs.h>

#define BP_VIC_ST       26
#define BP_VIC_RTC_TICK 29


// For avoiding ambiguous turnover of TICNTO
// This critia is just on 800MHz.
// If ARM_CLK is under 800MHz, this value must be adjusted.
#define MIN_IDLE_COUNT          240 // 20us
#define MIN_UPDATE_COUNT        600 // 50us 
#define MIN_UPATE_ICNTO_COUNT   24  // 02us 
#define MAX_UPATE_ICNTO_COUNT   11975 //02us
#define MIN_DIDLETIME                       4 // 4ms

extern void DeepIdle_Init(void);
extern BOOL DeepIdle_CheckEnterDeepIdle();
extern void OALCPUDeepIdle();
extern void OALCPUIdle_WFI(void);
extern void PreConfigureDeepIdle();


// Local Variables
volatile GPIO_REG *g_pGPIORegs = NULL;
volatile SYSTIMER_REG *g_pSYSTimerRegs = NULL;
volatile VIC_REG *g_pVIC0Regs = NULL;
volatile PMU_PM_REG *g_pPMUPMRegs = NULL;
volatile PMU_MISC_REG *g_pPMUMISCRegs = NULL;
static volatile BSP_ARGS    *TimerBSPArgs = NULL;

#ifdef BSP_USEDVFS
BOOL    bIntercepted = FALSE;
DWORD   gIDLESnapshot;
DWORD   gTotalSnapshot;
#endif // BSP_USEDVFS

// System timer can have some accuracy error while system tick is passed in long time period
// Added for compensation error by using RTC tick 
// In this case, RTC tick has to be accurated
#ifdef RTC_TICK_ERROR_COMPENSATION
volatile RTC_REG *g_pRTCRegs = NULL;
#endif

void InitSystemTimer(UINT32 countsPerSysTick)
{
    OALMSG(OAL_TIMER&&OAL_FUNC,(L"[OAL] ++InitSystemTimer\r\n"));
    
    //System Timer Reset
    OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) & ~(0x1<<16));
    OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | (0x1<<16));

    // Disable System Timer Interrupt
    DISABLE_SYSTEM_INTR(g_pSYSTimerRegs->INT_CSTAT);
        
    // Disable All Interrupts(TCON/ICNTB/TFCNTB/TICNTB Write INT, Interrupt Counter Expired INT) 
    DISABLE_ALL_INTR(g_pSYSTimerRegs->INT_CSTAT);
    
    // Set clock source(XusbXTI-24MHz)
    OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) & ~(0xf<<12));
    OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) |(0x2<<12));

    // Set Prescalar value
    OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) & ~(0xff));
    OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | SYS_TIMER_PRESCALER);
    
    OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) & ~(0x7<<8));

    switch(SYS_TIMER_DIVIDER)
    {
    case 1:
        OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | (0 << 8));  // SYS_TIMER_DIVIDER = 1
        break;
    case 2:
        OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | (1 << 8));  // SYS_TIMER_DIVIDER = 2
        break;
    case 4:
        OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | (2 << 8));  // SYS_TIMER_DIVIDER = 4
        break;
    case 8:
        OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | (3 << 8));  // SYS_TIMER_DIVIDER = 8
        break;
    case 16:
        OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | (4 << 8));  // SYS_TIMER_DIVIDER = 16
        break;
    default:
        OUTREG32(&g_pSYSTimerRegs->TCFG, INREG32(&g_pSYSTimerRegs->TCFG) | (0 << 8));  // SYS_TIMER_DIVIDER = 1
        break;
    }
    
    g_pVIC0Regs->VICINTENCLEAR |= (1<<BP_VIC_ST);

    // Enable ICNTB Expire Interrupt Enable
    ENABLE_ICNT_EXPIRE_INTR(g_pSYSTimerRegs->INT_CSTAT);

    // Set timer register //--------------------------------------------------------------------------------
    OUTREG32(&g_pSYSTimerRegs->TICNTB, countsPerSysTick - 1);      // TICK = 1ms
    WAIT_FOR_TICNTB_UPDATE(g_pSYSTimerRegs->INT_CSTAT);
#if(S5PV210_EVT==0)    
    OUTREG32(&g_pSYSTimerRegs->ICNTB, 0);                                    // INT = 1ms
    WAIT_FOR_ICNTB_UPDATE(g_pSYSTimerRegs->INT_CSTAT);

    OUTREG32(&g_pSYSTimerRegs->TCON, (0x1<<4)); //Update ICNTB
    WAIT_FOR_TCON_UPDATE(g_pSYSTimerRegs->INT_CSTAT);
#else
    OUTREG32(&g_pSYSTimerRegs->ICNTB, (0x1<<31) | 0);                                    // INT = 1ms
    WAIT_FOR_ICNTB_UPDATE(g_pSYSTimerRegs->INT_CSTAT);
#endif
    //////////-----------------------------------------------------------------------------------------
    OUTREG32(&g_pSYSTimerRegs->TCON, (0x20) ); // Auto Reload
    OUTREG32(&g_pSYSTimerRegs->TCON, (0x21) ); // Timer Start
    WAIT_FOR_TCON_UPDATE(g_pSYSTimerRegs->INT_CSTAT);
    OUTREG32(&g_pSYSTimerRegs->TCON, (0x29) ); // Timer Interrupt Start
    WAIT_FOR_TCON_UPDATE(g_pSYSTimerRegs->INT_CSTAT);

    // System Timer Clear Interrupt Pending
    CLEAR_SYSTEM_INTR(g_pSYSTimerRegs->INT_CSTAT);
    // System Timer Enable Interrupt
    ENABLE_SYSTEM_INTR(g_pSYSTimerRegs->INT_CSTAT);
    
    g_pVIC0Regs->VICINTENABLE |= (1<<BP_VIC_ST);


#ifdef RTC_TICK_ERROR_COMPENSATION

    // Generation RTC Tick interrupt by 1sec for accuracy test of system timer
    //RTC enable
    g_pVIC0Regs->VICINTENCLEAR |= (1<<BP_VIC_RTC_TICK);
    OUTREG32(&g_pRTCRegs->RTCCON, INREG32(&g_pRTCRegs->RTCCON) | 1<<0);
    //RTC Clock count reset
    OUTREG32(&g_pRTCRegs->RTCCON, INREG32(&g_pRTCRegs->RTCCON) & ~(1<<3));
    // RTC tick timer clock selection(32768Hz)
    OUTREG32(&g_pRTCRegs->RTCCON, INREG32(&g_pRTCRegs->RTCCON) & ~(0xF<<4));

    // RTC tick count(327679 = 10s)
    OUTREG32(&g_pRTCRegs->TICCNT, 327679);

    // RTC Tick pending clear
    OUTREG32(&g_pRTCRegs->INTP, 1<<0);
    // RTC Tick start
    OUTREG32(&g_pRTCRegs->RTCCON, INREG32(&g_pRTCRegs->RTCCON)| 1<<8);

    //RTCCON disable
    OUTREG32(&g_pRTCRegs->RTCCON, INREG32(&g_pRTCRegs->RTCCON) & ~(1<<0));
    g_pVIC0Regs->VICINTENABLE |= (1<<BP_VIC_RTC_TICK);
    OALMSG(1,(TEXT("System Timer Tick Compensation Start by 10 seconds\r\n")));
#endif    
 }

//------------------------------------------------------------------------------
//  Function: OALTimerInit
//
//  This function is typically called from the OEMInit to initialize
//  Windows CE system timer. The tickMSec parameter determine timer
//  period in milliseconds. On most platform timer period will be
//  1 ms, but it can be usefull to use higher value for some
//  specific (low-power) devices.
//
//  Implementation for S5PV210 is using timer 4 as system timer.
BOOL OALTimerInit(UINT32 msecPerSysTick, UINT32 countsPerMSec, UINT32 countsMargin)
{
    BOOL rc = FALSE;
    UINT32 countsPerSysTick;
    UINT32 sysIntr, irq;

#ifdef RTC_TICK_ERROR_COMPENSATION
    UINT32 sysIntr2, irq2; 
#endif
    g_pSYSTimerRegs = (volatile SYSTIMER_REG*)OALPAtoVA(BASE_REG_PA_SYSTIMER,FALSE);
    g_pGPIORegs = (volatile GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
    g_pVIC0Regs = (volatile VIC_REG*)OALPAtoVA(BASE_REG_PA_VIC0,FALSE);
    g_pPMUPMRegs = (volatile PMU_PM_REG *)OALPAtoVA(BASE_REG_PA_PMU_PM,FALSE);
    g_pPMUMISCRegs = (volatile PMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_PMU_MISC,FALSE);    
#ifdef RTC_TICK_ERROR_COMPENSATION
    g_pRTCRegs = (volatile RTC_REG*)OALPAtoVA(BASE_REG_PA_RTC, FALSE);
#endif  
    TimerBSPArgs = (volatile BSP_ARGS*)IMAGE_SHARE_ARGS_UA_START;

    DeepIdle_Init();
    // Validate Input parameters
    countsPerSysTick = countsPerMSec * msecPerSysTick;
    if(msecPerSysTick<1 || msecPerSysTick>1000 || countsPerSysTick<1 || countsPerSysTick>0xFFFFFFFF)
    {
        OALMSG(OAL_ERROR,(L"ERROR: OALTimerInit: System tick period out of range..."));
        goto cleanUp;
    }

    // Initialize timer state global variable
    g_oalTimer.msecPerSysTick = msecPerSysTick;         // miliseconds per system tick
    g_oalTimer.countsPerMSec = countsPerMSec;           // Clock tick  per miliseconds
    g_oalTimer.countsMargin = countsMargin;
    g_oalTimer.countsPerSysTick = countsPerSysTick;     // Clock tick  per system tick
    g_oalTimer.curCounts = 0;
    g_oalTimer.maxPeriodMSec = 0xFFFFFFFF/g_oalTimer.countsPerMSec;

    g_oalTimer.actualMSecPerSysTick = g_oalTimer.msecPerSysTick;
    g_oalTimer.actualCountsPerSysTick = g_oalTimer.countsPerSysTick;

    // Set kernel exported globals to initial values
    idleconv = countsPerMSec;
    curridlehigh = 0;
    curridlelow = 0;

    // Initialize high resolution timer function pointers
    pQueryPerformanceFrequency = OALTimerQueryPerformanceFrequency;
    pQueryPerformanceCounter = OALTimerQueryPerformanceCounter;

    // Initialize Variable System Tick reschedule time update function pointer
    pOEMUpdateRescheduleTime = OALTimerUpdateRescheduleTime;

    // Create SYSINTR for timer
    irq = IRQ_SYSTIMER;
    sysIntr = OALIntrRequestSysIntr(1, &irq, OAL_INTR_FORCE_STATIC);

#ifdef RTC_TICK_ERROR_COMPENSATION
    irq2 = IRQ_RTC_TIC;
    sysIntr2 = OALIntrRequestSysIntr(1, &irq2, OAL_INTR_FORCE_STATIC);
#endif
    InitSystemTimer(g_oalTimer.msecPerSysTick*g_oalTimer.countsPerMSec);

#ifdef BSP_USEDVFS
    ResetSnapshot(gTotalSnapshot, gIDLESnapshot);
    InitializeDVFS();
#endif // BSP_USEDVFS
    
    // Enable System Tick interrupt
    if (!OEMInterruptEnable(sysIntr, NULL, 0))
    {
        OALMSG(OAL_ERROR,(L"ERROR: OALTimerInit: Interrupt enable for system timer failed"));
        goto cleanUp;
    }

#ifdef RTC_TICK_ERROR_COMPENSATION
    if (!OEMInterruptEnable(sysIntr2, NULL, 0))
    {
        OALMSG(OAL_ERROR,(L"ERROR: OALTimerInit: Interrupt enable for timer2 failed"));
        goto cleanUp;
    }
#endif

    // Define ENABLE_WATCH_DOG to enable watchdog timer support.
    // NOTE: When watchdog is enabled, the device will reset itself if watchdog timer is not refreshed within ~4.5 second.
    //       Therefore it should not be enabled when kernel debugger is connected, as the watchdog timer will not be refreshed.
#ifdef ENABLE_WATCH_DOG
    {
        extern void SMDKInitWatchDogTimer (void);
        SMDKInitWatchDogTimer ();
    }
#endif

    rc = TRUE;

    cleanUp:
    OALMSG(OAL_TIMER, (L"-OALTimerInit(rc = %d)\r\n", rc));

    return rc;
}

//------------------------------------------------------------------------------
//
//  Function: OALIntrTimerUpdate
//

void OALIntrTimerUpdate(BOOL PreIdleUpdate, UINT32 period, UINT32 RefTICNTO)
{
    UINT32 elapsedTICNTO;
    
#if(S5PV210_EVT==0)   
    OUTREG32(&g_pSYSTimerRegs->ICNTB, period - 1);
    WAIT_FOR_ICNTB_UPDATE(g_pSYSTimerRegs->INT_CSTAT);

    OUTREG32(&g_pSYSTimerRegs->TCON, INREG32(&g_pSYSTimerRegs->TCON)|(0x1<<4));
    WAIT_FOR_TCON_UPDATE(g_pSYSTimerRegs->INT_CSTAT);
#else
    OUTREG32(&g_pSYSTimerRegs->ICNTB, (0x1<<31)|(period - 1));
    WAIT_FOR_ICNTB_UPDATE(g_pSYSTimerRegs->INT_CSTAT);
#endif

    elapsedTICNTO = g_pSYSTimerRegs->TICNTO;

    if(elapsedTICNTO >= RefTICNTO)
    {   
        if(!PreIdleUpdate)
        {
            if(!(g_pVIC0Regs->VICIRQSTATUS & 1<<BP_VIC_ST))
            {
                CurMSec += 1;
#ifdef BSP_USEDVFS
								UpdateTotalSnapshot(TimerBSPArgs, gTotalSnapshot, g_oalTimer.countsPerSysTick);
#endif                
            }
        }
     } 
}

//------------------------------------------------------------------------------
//  Function: OALTimerIntrHandler
//
//  This function implement timer interrupt handler. It is called from common
//  ARM interrupt handler.
UINT32 OALTimerIntrHandler()
{
    UINT32 sysIntr = SYSINTR_NOP;


#ifdef BSP_USEDVFS
    if(bIntercepted == TRUE)
    {
        SetIntercepted(bIntercepted, FALSE);
        sysIntr = SYSINTR_RESCHED;
        goto CleanUp_TimerHandler;
    }
#endif

    // Update high resolution counter
    g_oalTimer.curCounts += g_oalTimer.countsPerSysTick;

    // Update the millisecond counter
    CurMSec += g_oalTimer.msecPerSysTick;


#ifdef BSP_USEDVFS
    UpdateTotalSnapshot(TimerBSPArgs, gTotalSnapshot, g_oalTimer.countsPerSysTick);

    if(DVFSCHECK_BEFOREHAND(TimerBSPArgs))
    {
        if(DecideDVFS(gTotalSnapshot, gIDLESnapshot))
        {
            sysIntr = SYSINTR_DVFS;

            if (CurMSec  >= dwReschedTime)
            {
                SetIntercepted(bIntercepted, TRUE);
                return sysIntr;
            }
            else
            {
                SetIntercepted(bIntercepted, FALSE);
                goto CleanUp_TimerHandler;
            }
        }
    }
#endif

    // Reschedule?
    if (CurMSec  >= dwReschedTime) sysIntr = SYSINTR_RESCHED;

#ifdef OAL_ILTIMING
    if (g_oalILT.active)
    {
        if (--g_oalILT.counter == 0)
        {
            sysIntr = SYSINTR_TIMING;
            g_oalILT.counter = g_oalILT.counterSet;
            g_oalILT.isrTime2 = OALTimerCountsSinceSysTick();
        }
    }
#endif

#ifdef BSP_USEDVFS

CleanUp_TimerHandler:


    ExpireSnapshot(gTotalSnapshot, gIDLESnapshot);
#endif

    if (g_pSYSTimerRegs->INT_CSTAT & ST_INTR_STS) // (CurMSec == baseMSec)
    {
       CLEAR_SYSTEM_INTR(g_pSYSTimerRegs->INT_CSTAT);
    }
    else
    {
        OALMSG(1,(TEXT("Dummy(0x%x)\r\n"),g_pSYSTimerRegs->INT_CSTAT));
        CLEAR_ALL_INTR(g_pSYSTimerRegs->INT_CSTAT);
    }

    return sysIntr;
}

//------------------------------------------------------------------------------
//  Function: OALTimerCountsSinceSysTick
//
//  This function return count of hi res ticks since system tick.
//
//  Timer 4 counts down, so we should substract actual value from
//  system tick period.
INT32 OALTimerCountsSinceSysTick()
{
    return (INREG32(&g_pSYSTimerRegs->TICNTB) - INREG32(&g_pSYSTimerRegs->TICNTO));
}

//------------------------------------------------------------------------------
//
//  Function: OALTimerUpdate
//
//  This function is called to change length of actual system timer period.
//  If end of actual period is closer than margin period isn't changed (so
//  original period elapse). Function returns time which already expires
//  in new period length units. If end of new period is closer to actual time
//  than margin period end is shifted by margin (but next period should fix
//  this shift - this is reason why OALTimerRecharge doesn't read back
//  compare register and it uses saved value instead).
UINT32 OALTimerUpdate(UINT32 period, UINT32 margin)
{
    OALMSG(OAL_TIMER, (L"+OALTimerUpdate()\r\n"));
    return 0;
}

//------------------------------------------------------------------------------
//  Function:     OEMIdle
//
//  This function is called by the kernel when there are no threads ready to
//  run. The CPU should be put into a reduced power mode if possible and halted.
//  It is important to be able to resume execution quickly upon receiving an
//  interrupt.
//
//  Interrupts are disabled when OEMIdle is called and when it returns.
//
//  Note that system timer must be running when CPU/SoC is moved to reduced
//  power mode.
void OEMIdle(DWORD idleParam)
{
    UINT32 baseMSec, idleMSec;
    INT32 usedCounts, idleCounts;
    ULARGE_INTEGER idle;
    UINT32 baseICNTO, baseTICNTO;
    UINT32 elapsedICNTO, elapsedTICNTO;
    
    BOOL bTimerUpdated = FALSE;
    BOOL bTimerIntr = FALSE;
    BOOL bEnterDeepIdle = FALSE;
    UINT32  tempIdleCnt = 0;
 
    
    baseMSec = CurMSec;

    // Remained Idle Time
    if(baseMSec >= dwReschedTime) return;
    idleMSec = dwReschedTime -baseMSec;

    if(TimerBSPArgs->dwCreepModeInfo >= MIN_DIDLETIME)
    {
        // LP Driver working mode : SB
        if((MIN_DIDLETIME < idleMSec) && (idleMSec < TimerBSPArgs->dwCreepModeInfo))
        {
            TimerBSPArgs->bAugStateCreepMode = FALSE;  // SB
        }
        else if(TimerBSPArgs->dwCreepModeInfo <= idleMSec) // LP Driver working mode : LB
        {
            TimerBSPArgs->bAugStateCreepMode = TRUE;   // LB
        }
    }
    
    // Find how many hi-res ticks was already used
    usedCounts = OALTimerCountsSinceSysTick();

    if (usedCounts + MIN_IDLE_COUNT >= (INT32)g_oalTimer.countsPerSysTick)
    {
        return;
    }

    if(idleMSec > 1) //If the period of IDLE is more than 1ms, ICNTB of System timer should be reconfigured
    {
        baseTICNTO = g_pSYSTimerRegs->TICNTO;

        if(g_pVIC0Regs->VICIRQSTATUS & 1<<BP_VIC_ST)
            return;

        if(baseTICNTO < MIN_UPDATE_COUNT)
        {
            // Abandon Idle because there is no enough time to re-set the period of system timer.
            return;
        }
        else
        {
            OALIntrTimerUpdate(TRUE, idleMSec,g_pSYSTimerRegs->TICNTO);
            bTimerUpdated = TRUE;
        }

        usedCounts = OALTimerCountsSinceSysTick();
    }
    
    baseTICNTO = g_pSYSTimerRegs->TICNTO;
    baseICNTO = g_pSYSTimerRegs->ICNTO;
    tempIdleCnt = idleMSec * g_oalTimer.countsPerMSec;

    //Exception Hadling, 
    if(baseICNTO != g_pSYSTimerRegs->ICNTB)
    {
        baseICNTO = g_pSYSTimerRegs->ICNTB;
    }

#if (BSP_NOIDLE != 1)

    // Configure registers for entering deep idle in previous.. For Early WakeUp set PMU_INT_DISBALE 
    PreConfigureDeepIdle();
    
    // Enterning Deep Idle Mode replace of Idle mode in case of LP ADUIO Play Mode
   if(DeepIdle_CheckEnterDeepIdle()&&(idleMSec>MIN_DIDLETIME))
   {
        //Set STANDBYWFI for deep idle
        g_pPMUPMRegs->PWR_CONF.PWR_CFG = (g_pPMUPMRegs->PWR_CONF.PWR_CFG & ~(BW_CFG_STANDBYWFI<<BP_CFG_STANDBYWFI)) | (CFG_ENTER_IDLE<<BP_CFG_STANDBYWFI); 

        //set SYSCON_INT_DISABLE bit for early-wakeup
        g_pPMUMISCRegs->SYS_CON.OTHERS |= (1<<BP_OTHERS_SYSCON_INT_DISABLE);

        bEnterDeepIdle = TRUE;
        OALCPUDeepIdle();
   }
   else
   {
        // Set Idle_cfg for normal idle
        g_pPMUPMRegs->PWR_CONF.IDLE_CFG = (g_pPMUPMRegs->PWR_CONF.IDLE_CFG & ~((BW_CFG_DIDLE<<BP_CFG_DIDLE)));    
#ifdef TIMER_LED_DISPLAY
        Set_PinData(g_pGPIORegs, LED8, 1);
#endif 
        OALCPUIdle_WFI();
#ifdef TIMER_LED_DISPLAY
        Set_PinData(g_pGPIORegs, LED8, 0);  
#endif
    }
#endif
    
    elapsedTICNTO = g_pSYSTimerRegs->TICNTO;    
    if(elapsedTICNTO < MIN_UPATE_ICNTO_COUNT)
    {
        do{
            elapsedTICNTO = g_pSYSTimerRegs->TICNTO;
           }while((elapsedTICNTO < MIN_UPATE_ICNTO_COUNT)||(elapsedTICNTO == 0)||(elapsedTICNTO > MAX_UPATE_ICNTO_COUNT));
    }
    
    elapsedICNTO = g_pSYSTimerRegs->ICNTO;

    if(g_pVIC0Regs->VICIRQSTATUS & 1<<BP_VIC_ST)    // Wakeup by timer interrupt
    {
         idleCounts = tempIdleCnt - usedCounts;
         CurMSec  += (idleMSec-1); // After escaping OEMIdle(), TimerISR add 1ms to CurMSec
         tempIdleCnt = tempIdleCnt - g_oalTimer.countsPerMSec;
         g_oalTimer.curCounts += tempIdleCnt;
#ifdef BSP_USEDVFS
	 UpdateTotalSnapshot(TimerBSPArgs, gTotalSnapshot, tempIdleCnt);
#endif
         if(bEnterDeepIdle)
         {
            if(elapsedICNTO != baseTICNTO)
            {
                tempIdleCnt = (baseICNTO - elapsedICNTO)*g_oalTimer.countsPerMSec;
                CurMSec += (baseICNTO - elapsedICNTO);
                idleCounts += tempIdleCnt + OALTimerCountsSinceSysTick();
                g_oalTimer.curCounts += tempIdleCnt + OALTimerCountsSinceSysTick();
#ifdef BSP_USEDVFS
		UpdateTotalSnapshot(TimerBSPArgs, gTotalSnapshot, (tempIdleCnt + OALTimerCountsSinceSysTick()));
#endif                
            }
         }
    }
    else
    {
        idleMSec = baseICNTO - elapsedICNTO;
        tempIdleCnt = idleMSec*g_oalTimer.countsPerMSec;
        idleCounts = tempIdleCnt - usedCounts + OALTimerCountsSinceSysTick();
        CurMSec   += (idleMSec);
        g_oalTimer.curCounts += tempIdleCnt;
#ifdef BSP_USEDVFS
	 UpdateTotalSnapshot(TimerBSPArgs, gTotalSnapshot, tempIdleCnt);
#endif
        
    }
 
    if(bTimerUpdated)
    {
        OALIntrTimerUpdate(FALSE, g_oalTimer.msecPerSysTick,elapsedTICNTO);
    }

#ifdef BSP_USEDVFS
    UpdateIdleSnapshot(TimerBSPArgs, gIDLESnapshot, idleCounts);
#endif    

    idle.LowPart = curridlelow;
    idle.HighPart = curridlehigh;
    idle.QuadPart += idleCounts;
    curridlelow  = idle.LowPart;
    curridlehigh = idle.HighPart;
    
}

void OALTimerUpdateRescheduleTime(DWORD time)
{

}

