//
// 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.
//
// NOTE: stubs are being used - this isn't done

#include <windows.h>
#include <pmplatform.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"

//#define SLEEP_AGING_TEST
#ifndef NO_USE_CEC
#define HDMI_CEC_WAKEUP_SORUCE
#endif

// About following value, refer to the Button.c and PowerButton.c
#define EINT_POWER_BUTTON   EXT_INT_31
#define WAKEUP_PWR_BUTTON           BP_EINT31_WAKEUP_MASK

#ifndef NO_USE_TVOUT
#define EINT_HPD   EXT_INT_13
#define WAKEUP_HDMI_HPD           BP_EINT13_WAKEUP_MASK
#endif

static UINT32 g_aSleepSave_VIC[100];
static UINT32 g_aSleepSave_DMACon[10];
static UINT32 g_aSleepSave_GPIO[(GPIO_TOTALNUM*GPIO_GROUPNUM)+(MP_TOTALNUM*MP_GROUPNUM)+(ETC_TOTALNUM*ETC_GROUPNUM)+(GPIO_EINT_NUM*5)+(3+16)+10];
static UINT32 g_aSleepSave_SysCon[100];
static UINT32 g_aSleepSave_PMU[10];

static void InitializeOTGCLK(void);
// Vector Address Table Initialize Function in "\SEC_V1\OAL\INTR\intr.c"
extern void VICTableInit(void);
// Tick Timer initialize function
extern void InitSystemTimer(UINT32 countsPerSysTick);

extern void CPUSleepMode();

static void SaveState_VIC(void *pVIC0, void *pVIC1, void *pVIC2, void *pVIC3, UINT32 *pBuffer)
{
    volatile VIC_REG *pVIC0Reg;
    volatile VIC_REG *pVIC1Reg;
    volatile VIC_REG *pVIC2Reg;
    volatile VIC_REG *pVIC3Reg;

    pVIC0Reg = (VIC_REG *)pVIC0;
    pVIC1Reg = (VIC_REG *)pVIC1;
    pVIC2Reg = (VIC_REG *)pVIC2;
    pVIC3Reg = (VIC_REG *)pVIC3;

    *pBuffer++ = pVIC0Reg->VICINTSELECT;
    *pBuffer++ = pVIC0Reg->VICINTENABLE;
    *pBuffer++ = pVIC0Reg->VICSOFTINT;
	*pBuffer++ = pVIC0Reg->VICVECTPRIORITY26;

    *pBuffer++ = pVIC1Reg->VICINTSELECT;
    *pBuffer++ = pVIC1Reg->VICINTENABLE;
    *pBuffer++ = pVIC1Reg->VICSOFTINT;

    *pBuffer++ = pVIC2Reg->VICINTSELECT;
    *pBuffer++ = pVIC2Reg->VICINTENABLE;
    *pBuffer++ = pVIC2Reg->VICSOFTINT;

    *pBuffer++ = pVIC3Reg->VICINTSELECT;
    *pBuffer++ = pVIC3Reg->VICINTENABLE;
    *pBuffer++ = pVIC3Reg->VICSOFTINT;

    // Do not Save VICVECTADDRXX
    // Reinitialize Vector Address Table with VICTableInit()
}

static void RestoreState_VIC(void *pVIC0, void *pVIC1, void *pVIC2, void *pVIC3, UINT32 *pBuffer)
{
    volatile VIC_REG *pVIC0Reg;
    volatile VIC_REG *pVIC1Reg;
    volatile VIC_REG *pVIC2Reg;
    volatile VIC_REG *pVIC3Reg;

	VICTableInit();

    pVIC0Reg = (VIC_REG *)pVIC0;
    pVIC1Reg = (VIC_REG *)pVIC1;
    pVIC2Reg = (VIC_REG *)pVIC2;
    pVIC3Reg = (VIC_REG *)pVIC3;

    pVIC0Reg->VICINTSELECT = *pBuffer++;
    pVIC0Reg->VICINTENABLE = *pBuffer++;
    pVIC0Reg->VICSOFTINT   = *pBuffer++;
	pVIC0Reg->VICVECTPRIORITY26 = *pBuffer++;

    pVIC1Reg->VICINTSELECT = *pBuffer++;
    pVIC1Reg->VICINTENABLE = *pBuffer++;
    pVIC1Reg->VICSOFTINT   = *pBuffer++;

    pVIC2Reg->VICINTSELECT = *pBuffer++;
    pVIC2Reg->VICINTENABLE = *pBuffer++;
    pVIC2Reg->VICSOFTINT   = *pBuffer++;

    pVIC3Reg->VICINTSELECT = *pBuffer++ ;
    pVIC3Reg->VICINTENABLE = *pBuffer++ ; 
    pVIC3Reg->VICSOFTINT   = *pBuffer++ ;
    

}


static void SaveState_DMACon(void *pPDMAC0, void *pPDMAC1, void *pMDMAC, UINT32 *pBuffer)
{
    volatile DMAC_REG *pPDMAC0Reg;
    volatile DMAC_REG *pPDMAC1Reg;
    volatile DMAC_REG *pMDMACReg;

    pPDMAC0Reg = (DMAC_REG *)pPDMAC0;
    pPDMAC1Reg = (DMAC_REG *)pPDMAC1;
    pMDMACReg = (DMAC_REG *)pMDMAC;


    *pBuffer++ = pPDMAC0Reg->IntEnable;
    *pBuffer++ = pPDMAC1Reg->IntEnable;
    *pBuffer++ = pMDMACReg->IntEnable;

}

static void RestoreState_DMACon(void *pPDMAC0, void *pPDMAC1, void *pMDMAC, UINT32 *pBuffer)
{
    volatile DMAC_REG *pPDMAC0Reg;
    volatile DMAC_REG *pPDMAC1Reg;
    volatile DMAC_REG *pMDMACReg;

    pPDMAC0Reg = (DMAC_REG *)pPDMAC0;
    pPDMAC1Reg = (DMAC_REG *)pPDMAC1;
    pMDMACReg = (DMAC_REG *)pMDMAC;

    pPDMAC0Reg->IntEnable = *pBuffer++;
    pPDMAC1Reg->IntEnable = *pBuffer++;
    pMDMACReg->IntEnable = *pBuffer++;
}

static void SaveState_GPIO(void *pGPIO, UINT32 *pBuffer)
{

    volatile GPIO_REG *pGPIOReg;
    UINT32 i, j;
    volatile UINT32 *pGPIORegAddr;
    volatile PMU_MISC_REG *pPMUMiscReg; 
    pPMUMiscReg = (PMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_PMU_MISC, FALSE);

    pGPIOReg = (GPIO_REG *)pGPIO;

    //---------------------------------------------------------------------
    // Save GPIO Registers.
    // : GPA0 ~ GPJ4  [0x0   ~ 0x2D4]
    pGPIORegAddr = (volatile UINT32 *)pGPIO;    
    for(i=0; i<(GPIO_TOTALNUM); i++)  {
        for(j=0; j<GPIO_GROUPNUM; j++)
        {            // save only 6 registers per each gpio
            *pBuffer++ = *pGPIORegAddr++;
        }            
        pGPIORegAddr += 2;
    }  

    // MP0_1 ~ MP2_8
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->MP0_1.MP_CON);
    for(i = 0 ; i < (MP_TOTALNUM); i++)
    {
        for(j = 0 ; j < MP_GROUPNUM; j++)
        {
            *pBuffer++ = *pGPIORegAddr++;
        }
        pGPIORegAddr += 2;
    }

    // ETC0 ~ ETC4
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->ETC0.ETC_PUD);
    for(i = 0 ; i < (ETC_TOTALNUM) ; i++)
    {
        for(j = 0 ; j < ETC_GROUPNUM ; j++)
        {
            *pBuffer++ = *pGPIORegAddr++;
        }
        pGPIORegAddr += 6;
    }
    
    //---------------------------------------------------------------------
    // Save GPIO_INT_CON Registers.
    // : GPA0_INT ~ GPJ4_INT  [0x700 ~ 0x754]
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTCON.GPA0_INT_CON);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
            *pBuffer++ = *pGPIORegAddr++;
    }

    //---------------------------------------------------------------------
    // Save GPIO_INT_FILTER_CON Registers.
    // : GPA0_INT ~ GPJ4_INT  [0x800 ~ 0x8AC]
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTFLT.GPA0_INT_FLT_CON);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
        for(j=0;j<2;j++)
            *pBuffer++ = *pGPIORegAddr++;
    }
    
    //---------------------------------------------------------------------
    // Save GPIO_INT_MASK Registers.
    // : GPA0_INT ~ GPJ4_INT  [0x900 ~ 0x954]
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTMSK.GPA0_INT_MASK);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
            *pBuffer++ = *pGPIORegAddr++;
    }

    //---------------------------------------------------------------------
    // Save GPIO_INT_GRP Registers.
    // : GPIO_INT_GRPPRI, GPIOINT_PRIORITY, GPIOINT_GRPFIXPRI
    *pBuffer++ = pGPIOReg->GPIOINT_GRPPRI;
    *pBuffer++ = pGPIOReg->GPIOINT_PRIORITY;
    *pBuffer++ = pGPIOReg->GPIOINT_GRPFIXPRI;

    //---------------------------------------------------------------------
    // Save GPIO_INT_FIXPRI Registers.
    // : GPA0 ~ GPJ4  [0xB14 ~ 0xB68]
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTFIXPRI.GPA0_INT_FIXPRI);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
            *pBuffer++ = *pGPIORegAddr++;
    }

    //---------------------------------------------------------------------
    // GPIOH0~GPIPOH3 Registers.
    // : These registers are retentioned.
    //   So you don't need to save or restore there values.


    //---------------------------------------------------------------------
    // Save External Interrupt Control register fo wakeup sources.
    //
    *pBuffer++ = pGPIOReg->EINTCON.EXT_INT0_CON;      //E00
    *pBuffer++ = pGPIOReg->EINTCON.EXT_INT1_CON;      //E04
    *pBuffer++ = pGPIOReg->EINTCON.EXT_INT2_CON;      //E08
    *pBuffer++ = pGPIOReg->EINTCON.EXT_INT3_CON;      //E0C

    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT0_CON._FLT_CON0;  //E80
    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT0_CON._FLT_CON1;  //E84
    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT1_CON._FLT_CON0;  //E88
    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT1_CON._FLT_CON1;  //E8C
    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT2_CON._FLT_CON0;  //E90
    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT2_CON._FLT_CON1;  //E94
    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT3_CON._FLT_CON0;  //E98
    *pBuffer++ = pGPIOReg->EINTFLT.EXT_FLT3_CON._FLT_CON1;  //E9C

    *pBuffer++ = pGPIOReg->EINTMSK.EXT_INT0_MASK;     //F00
    *pBuffer++ = pGPIOReg->EINTMSK.EXT_INT1_MASK;     //F04
    *pBuffer++ = pGPIOReg->EINTMSK.EXT_INT2_MASK;     //F08
    *pBuffer++ = pGPIOReg->EINTMSK.EXT_INT3_MASK;     //F0C

    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_GPIO;        // ENABLE_GPIO
#if (S5PV210_EVT>0)    
    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_CF_IO;        // ENABLE_CF_IO
#endif
    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_MMC_IO;        // ENABLE_MMC_IO
    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_UART_IO;        // ENABLE_UART_IO
}

static void RestoreState_GPIO(void *pGPIO, UINT32 *pBuffer)
{
    volatile GPIO_REG *pGPIOReg;
    UINT32 i, j;
    volatile UINT32 *pGPIORegAddr;
    volatile PMU_MISC_REG *pPMUMiscReg; 
    pPMUMiscReg = (PMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_PMU_MISC, FALSE);

    pGPIOReg = (GPIO_REG *)pGPIO;

    //---------------------------------------------------------------------
    // Restore GPIO Registers.
    // : GPA0 ~ GPJ4  [0x0   ~ 0x2D4]
    pGPIORegAddr = (volatile UINT32 *)pGPIO;    
    for(i=0; i<(GPIO_TOTALNUM); i++)  
    {
       *(pGPIORegAddr+1) = *(pBuffer+1);   // Restore DAT register
       *(pGPIORegAddr) = *(pBuffer);       // Restore CON register
       *(pGPIORegAddr+2) = *(pBuffer+2);   // Restore PUD register
       *(pGPIORegAddr+3) = *(pBuffer+3);   // Restore DRV register
       *(pGPIORegAddr+4) = *(pBuffer+4);   // Restore CONPDN register
       *(pGPIORegAddr+5) = *(pBuffer+5);   // Restore PUDPDN register

       pGPIORegAddr += 8;
       pBuffer          += 6;
    }

    // MP0_1 ~ MP2_8
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->MP0_1.MP_CON);
    for(i = 0 ; i < (MP_TOTALNUM); i++)
    {
        for(j = 0 ; j < MP_GROUPNUM; j++)
        {
            *pGPIORegAddr++ = *pBuffer++;
        }
        pGPIORegAddr += 2;
    }

    // ETC0 ~ ETC4
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->ETC0.ETC_PUD);
    for(i = 0 ; i < (ETC_TOTALNUM) ; i++)
    {
        for(j = 0 ; j < ETC_GROUPNUM ; j++)
        {
            *pGPIORegAddr++ = *pBuffer++;
        }
        pGPIORegAddr += 6;
    }
    
    //---------------------------------------------------------------------
    // Restore GPIO_INT_CON Registers.
    // : GPA0_INT ~ GPJ4_INT  [0x700 ~ 0x754] 
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTCON.GPA0_INT_CON);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
            *pGPIORegAddr++ = *pBuffer++;
    }

    //---------------------------------------------------------------------
    // Restore GPIO_INT_FILTER_CON Registers.
    // : GPA0_INT ~ GPJ4_INT  [0x800 ~ 0x8AC]
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTFLT.GPA0_INT_FLT_CON);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
        for(j=0;j<2;j++)
            *pGPIORegAddr++ = *pBuffer++;
    }

    //---------------------------------------------------------------------
    // Restore GPIO_INT_MASK Registers.
    // : GPA0_INT ~ GPJ4_INT  [0x900 ~ 0x954]
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTMSK.GPA0_INT_MASK);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
            *pGPIORegAddr++ = *pBuffer++;
    }

    //---------------------------------------------------------------------
    // Restore GPIO_INT_GRP Registers.
    // : GPIO_INT_GRPPRI, GPIOINT_PRIORITY [0xB00 ~ 0xB04]
    pGPIOReg->GPIOINT_GRPPRI = *pBuffer++;
    pGPIOReg->GPIOINT_PRIORITY = *pBuffer++;
    pGPIOReg->GPIOINT_GRPFIXPRI = *pBuffer++;

    //---------------------------------------------------------------------
    // Restore GPIO_INT_FIXPRI Registers.
    // : GPA0 ~ GPJ4  [0xB14 ~ 0xB68]
    pGPIORegAddr = (volatile UINT32 *)&(pGPIOReg->GPIOINTFIXPRI.GPA0_INT_FIXPRI);
    for(i=0; i<(GPIO_EINT_NUM); i++)  {
            *pGPIORegAddr++ = *pBuffer++;
    }

    //---------------------------------------------------------------------
    // GPIOH0~GPIPOH3 Registers.
    // : These registers are retentioned.
    //   So you don't need to save or restore there values.


    //---------------------------------------------------------------------
    // Save External Interrupt Control register fo wakeup sources.
    //
    pGPIOReg->EINTCON.EXT_INT0_CON = *pBuffer++;      //E00
    pGPIOReg->EINTCON.EXT_INT1_CON = *pBuffer++;      //E04
    pGPIOReg->EINTCON.EXT_INT2_CON = *pBuffer++;      //E08
    pGPIOReg->EINTCON.EXT_INT3_CON = *pBuffer++;      //E0C

    pGPIOReg->EINTFLT.EXT_FLT0_CON._FLT_CON0 = *pBuffer++;  //E80
    pGPIOReg->EINTFLT.EXT_FLT0_CON._FLT_CON1 = *pBuffer++;  //E84
    pGPIOReg->EINTFLT.EXT_FLT1_CON._FLT_CON0 = *pBuffer++;  //E88
    pGPIOReg->EINTFLT.EXT_FLT1_CON._FLT_CON1 = *pBuffer++;  //E8C
    pGPIOReg->EINTFLT.EXT_FLT2_CON._FLT_CON0 = *pBuffer++;  //E90
    pGPIOReg->EINTFLT.EXT_FLT2_CON._FLT_CON1 = *pBuffer++;  //E94
    pGPIOReg->EINTFLT.EXT_FLT3_CON._FLT_CON0 = *pBuffer++;  //E98
    pGPIOReg->EINTFLT.EXT_FLT3_CON._FLT_CON1 = *pBuffer++;  //E9C

    pGPIOReg->EINTMSK.EXT_INT0_MASK = *pBuffer++;     //F00
    pGPIOReg->EINTMSK.EXT_INT1_MASK = *pBuffer++;     //F04
    pGPIOReg->EINTMSK.EXT_INT2_MASK = *pBuffer++;     //F08
    pGPIOReg->EINTMSK.EXT_INT3_MASK = *pBuffer++;     //F0C

    // Disable ENAGLE_GPIO (Retention GPIO)
    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_GPIO;        // ENABLE_GPIO
#if (S5PV210_EVT>0)    
    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_CF_IO;        // ENABLE_CF_IO
#endif
    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_MMC_IO;        // ENABLE_MMC_IO
    pPMUMiscReg->SYS_CON.OTHERS |= ENABLE_UART_IO;        // ENABLE_UART_IO
}

#if (S5PV210_EVT==0)
static void SaveState_CMU(void *pCMUClk, void *pCMUSys, void *pCMUMisc, UINT32 *pBuffer)
#else
static void SaveState_CMU(void *pCMUClk, void *pCMUMisc, UINT32 *pBuffer)
#endif
{
    volatile UINT32 *pCMURegAddr;
    volatile CMU_CLK_REG *pCMUClkReg;
#if (S5PV210_EVT==0)    
    volatile CMU_SYS_REG *pCMUSysReg;
#endif
    volatile CMU_MISC_REG *pCMUMiscReg;
    UINT32 i;

    pCMUClkReg = (CMU_CLK_REG *)pCMUClk;
#if (S5PV210_EVT==0)     
    pCMUSysReg = (CMU_SYS_REG *)pCMUSys;
#endif
    pCMUMiscReg = (CMU_MISC_REG *)pCMUMisc;

    //---------------------------------------------------------------------
    // Save Clock Control Registers.
    // : At wake-up state, PLL registers will be reconfigured.
    //   So we just need to save the CLR_SRC/DIV/OutPut/Gate registers in this routine.

    //---------------------------------------------------------------------
    // Save CLK_SRC Registers.
    // : CLK_SRC0 ~ CLK_SRC6  [0x200 ~ 0x218]
    pCMURegAddr = (volatile UINT32 *)&( pCMUClkReg->CLK_SRC );
    for(i=0; i<7; i++)  {
        *pBuffer++ = *pCMURegAddr++;
    }
    *pBuffer++ = pCMUClkReg->CLK_SRC.CLK_SRC_MASK0;
    *pBuffer++ = pCMUClkReg->CLK_SRC.CLK_SRC_MASK1;

    //---------------------------------------------------------------------
    // Save CLK_DIV Registers.
    // : CLK_DIV0 ~ CLK_DIV7  [0x300 ~ 0x31C]
    pCMURegAddr = (volatile UINT32 *)&( pCMUClkReg->CLK_DIV );
    for(i=0; i<8; i++)  {
        *pBuffer++ = *pCMURegAddr++;
    }

    //---------------------------------------------------------------------
    // Save CLK_GATE_IP Registers.
    // : CLK_GATE_IP0 ~ CLK_GATE_IP4  [0x460 ~ 0x470]
    pCMURegAddr = (volatile UINT32 *)&( pCMUClkReg->CLK_GATE.CLK_GATE_IP0 );
    for(i=0; i<5; i++)  {
        *pBuffer++ = *pCMURegAddr++;
    }
    *pBuffer++ = pCMUClkReg->CLK_GATE.CLK_GATE_BLOCK;
    *pBuffer++ = pCMUClkReg->CLK_OUTPUT.CLK_OUT;

    //---------------------------------------------------------------------
    // Save CMU-memcfg Registers.
    // :
#if(S5PV210_EVT==0)
    *pBuffer++ = pCMUSysReg->MEM_REG.DMC0_CFG;
#endif

    //---------------------------------------------------------------------
    // Save CMU-misc Registers.
    // :
    *pBuffer++ = pCMUMiscReg->MULTIMEDIA.CAM_MUX_SEL;
    *pBuffer++ = pCMUMiscReg->MULTIMEDIA.MIXER_OUT_SEL;
    *pBuffer++ = pCMUMiscReg->MULTIMEDIA.DISPLAY_CONTROL;
    *pBuffer++ = pCMUMiscReg->MULTIMEDIA.AUDIO_ENDIAN;

    *pBuffer++ = pCMUMiscReg->TEST_REG.MIPI_PHY_CON0;
    *pBuffer++ = pCMUMiscReg->TEST_REG.MIPI_PHY_CON1;
    *pBuffer++ = pCMUMiscReg->TEST_REG.HDMI_PHY_CON0;

    //---------------------------------------------------------------------
    // Save Power Management Registers.
    // : These PMU registers are retentioned.
    //   So you don't need to save or restore there values.
    //   For more details, refer the table 2.4-10 of user's manual.

}

#if (S5PV210_EVT==0)
static void RestoreState_CMU(void *pCMUClk, void *pCMUSys, void *pCMUMisc, UINT32 *pBuffer)
#else
static void RestoreState_CMU(void *pCMUClk, void *pCMUMisc, UINT32 *pBuffer)
#endif
{

    volatile UINT32 *pCMURegAddr;
    volatile CMU_CLK_REG *pCMUClkReg;
#if (S5PV210_EVT==0)    
    volatile CMU_SYS_REG *pCMUSysReg;
#endif
    volatile CMU_MISC_REG *pCMUMiscReg;
    UINT32 i;

    pCMUClkReg = (CMU_CLK_REG *)pCMUClk;
#if (S5PV210_EVT==0)
    pCMUSysReg = (CMU_SYS_REG *)pCMUSys;
#endif
    pCMUMiscReg = (CMU_MISC_REG *)pCMUMisc;

    //---------------------------------------------------------------------
    // Restore Clock Control Registers.
    // : At wake-up state, PLL registers will be reconfigured.
    //   So we just need to restore the CLR_SRC/DIV/OutPut/Gate registers in this routine.

    //---------------------------------------------------------------------
    // Restore CLK_SRC Registers.
    // : CLK_SRC0 ~ CLK_SRC6  [0x200 ~ 0x218]
    pCMURegAddr = (volatile UINT32 *)&( pCMUClkReg->CLK_SRC );
    for(i=0; i<7; i++)  {
        *pCMURegAddr++ = *pBuffer++;
    }

    pCMUClkReg->CLK_SRC.CLK_SRC_MASK0 = *pBuffer++;
    pCMUClkReg->CLK_SRC.CLK_SRC_MASK1 = *pBuffer++;

    //---------------------------------------------------------------------
    // Restore CLK_DIV Registers.
    // : CLK_DIV0 ~ CLK_DIV7  [0x300 ~ 0x31C]
    pCMURegAddr = (volatile UINT32 *)&( pCMUClkReg->CLK_DIV );
    for(i=0; i<8; i++)  {
        *pCMURegAddr++ = *pBuffer++;
    }

    //---------------------------------------------------------------------
    // Restore CLK_GATE_IP Registers.
    // : CLK_GATE_IP0 ~ CLK_GATE_IP4  [0x460 ~ 0x470]
    pCMURegAddr = (volatile UINT32 *)&( pCMUClkReg->CLK_GATE.CLK_GATE_IP0 );
    for(i=0; i<5; i++)  {
        *pCMURegAddr++ = *pBuffer++;
    }
    pCMUClkReg->CLK_GATE.CLK_GATE_BLOCK = *pBuffer++;
    pCMUClkReg->CLK_OUTPUT.CLK_OUT = *pBuffer++;


    //---------------------------------------------------------------------
    // Restore CMU-memcfg Registers.
    // :
#if(S5PV210_EVT==0)
    pCMUSysReg->MEM_REG.DMC0_CFG = *pBuffer++;
#endif

    //---------------------------------------------------------------------
    // Restore CMU-misc Registers.
    // :
    pCMUMiscReg->MULTIMEDIA.CAM_MUX_SEL = *pBuffer++;
    pCMUMiscReg->MULTIMEDIA.MIXER_OUT_SEL = *pBuffer++;
    pCMUMiscReg->MULTIMEDIA.DISPLAY_CONTROL = *pBuffer++;
    pCMUMiscReg->MULTIMEDIA.AUDIO_ENDIAN = *pBuffer++;

    pCMUMiscReg->TEST_REG.MIPI_PHY_CON0 = *pBuffer++;
    pCMUMiscReg->TEST_REG.MIPI_PHY_CON1 = *pBuffer++;
    pCMUMiscReg->TEST_REG.HDMI_PHY_CON0 = *pBuffer++;

    //---------------------------------------------------------------------
    // Restore Power Management Registers.
    // : These PMU registers are retentioned.
    //   So you don't need to save or restore there values.
    //   For more details, refer the table 2.4-13 of user's manual.

}

static void SaveState_PMU(void *pPMUPM, UINT32 *pBuffer)
{
    volatile PMU_PM_REG *pPMUPMReg;

    pPMUPMReg = (PMU_PM_REG *)pPMUPM;

    *pBuffer++ = pPMUPMReg->STABLE_REG.CLAMP_STABLE;
}

static void RestoreState_PMU(void *pPMUPM, UINT32 *pBuffer)
{
    volatile PMU_PM_REG *pPMUPMReg;

    pPMUPMReg = (PMU_PM_REG *)pPMUPM;

    pPMUPMReg->STABLE_REG.CLAMP_STABLE = *pBuffer++;
}

static void SetWakeupSource(void)
{
    volatile PMU_PM_REG *pPMUPMReg;
    //volatile GPIO_REG *pGPIOReg;
    volatile BSP_ARGS *pBSPArgs;
#ifdef    SLEEP_AGING_TEST
    volatile RTC_REG *pRTCReg;
    SYSTEMTIME SysTime;
#endif

    pPMUPMReg = (PMU_PM_REG *)OALPAtoVA(BASE_REG_PA_PMU_PM, FALSE);
    //pGPIOReg  = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
    pBSPArgs  = (volatile BSP_ARGS*)IMAGE_SHARE_ARGS_UA_START;
#ifdef    SLEEP_AGING_TEST
    pRTCReg   = (RTC_REG *)OALPAtoVA(BASE_REG_PA_RTC, FALSE);
#endif

    //---------------------------------------------------------------------
    // Wake Up Source Mask
    pPMUPMReg->PWR_CONF.WAKEUP_MASK &= ~(BP_WAKEUP_ALL_MASK);
    pPMUPMReg->PWR_CONF.WAKEUP_MASK |= ((ENABLE_WAKEUP_SRC << BP_RTC_ALARM_WAKEUP_MASK) |
                                        (DISABLE_WAKEUP_SRC << BP_RTC_TICK_WAKEUP_MASK) |                                       
                                        (DISABLE_WAKEUP_SRC << BP_KEYIF_WAKEUP_MASK)    |
#ifdef HDMI_CEC_WAKEUP_SORUCE
                                        (ENABLE_WAKEUP_SRC << BP_HDMICEC_WAKEUP_MASK));
#else
                                        (DISABLE_WAKEUP_SRC << BP_HDMICEC_WAKEUP_MASK));
#endif
    //---------------------------------------------------------------------
    // Configrue External Interrupt : In the SMDKV210 board, the EINT31 is used as a power button.
    // : Power Button EINT[31] (GPH3[7] is Retention Port)
    pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK = BP_EINT_WAKEUP_ALL_MASK;
    pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK &= ~(1<<WAKEUP_PWR_BUTTON);    // enable Power Button



	//GPH0[1]  GPH0[2] GPH0[3]
	pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK &= ~(1<<2);    // enable Power Button
	pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK &= ~(1<<3);    // enable Power Button

	pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK &= ~(1<<1);    // enable Power Button

	
#ifndef NO_USE_TVOUT
    pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK &= ~(1<<WAKEUP_HDMI_HPD);    // enable HDMI_HPD
//    Set_EXTINT_TRLVL(pGPIOReg, EINT_POWER_BUTTON, sgip_BOTH_EDGE);

#endif

    //---------------------------------------------------------------------
    // Configure RTC Tick Timer
    // : We use RTC Tick when testing SLEEP_AGING.
#ifdef    SLEEP_AGING_TEST
	
    OEMGetRealTime(&SysTime);

    OALMSG(TRUE,(L"RTC Alarm (%d.%d.%d, %d:%d:%d, (%d th day of week)\r\n", \
    SysTime.wYear, SysTime.wMonth,  SysTime.wDay,    \
    SysTime.wHour, SysTime.wMinute, SysTime.wSecond,    \
    SysTime.wDayOfWeek
    ));

    SysTime.wSecond += 5;
    if(SysTime.wSecond>=60){
       SysTime.wSecond-=60; 
       SysTime.wMinute += 1;
    }
	if( SysTime.wMinute >= 60){
        SysTime.wHour += 1;
		SysTime.wMinute -=60;
		if(SysTime.wHour > 23){
			SysTime.wHour = 0;
            SysTime.wDay += 1;
	    }
    }
		
    OEMSetAlarmTime(&SysTime);
    
    OALMSG(TRUE,(L"RTC Alarm (%d.%d.%d, %d:%d:%d, (%d th day of week)\r\n", \
    SysTime.wYear, SysTime.wMonth,  SysTime.wDay,    \
    SysTime.wHour, SysTime.wMinute, SysTime.wSecond,    \
    SysTime.wDayOfWeek
    ));
    
    //pRTCReg->TICCNT = 0x4000;       // 0.5 sec @ 32.768KHz
    //pRTCReg->RTCCON |= (1<<8);      // Tick Timer Enable
#endif
    //---------------------------------------------------------------------
    // Clear All Wake Up Status bits
    // : This is cleared by writing 1.
    pPMUPMReg->STATUS_REG.WAKEUP_STAT = BP_WAKEUP_STAT_ALL_MASK;
    
    //For entering into sleep in Deep Idle
    pBSPArgs->bLPAudioEn = FALSE;

}

static UINT32 g_LastWakeupStatus = 0;
extern volatile UINT32 g_oalWakeSource;

static void GetWakeupSource(void)
{
    volatile PMU_PM_REG *pPMUPMReg;
    volatile GPIO_REG *pGPIOReg;
#ifdef    SLEEP_AGING_TEST
    volatile RTC_REG *pRTCReg;
#endif

    pPMUPMReg = (PMU_PM_REG *)OALPAtoVA(BASE_REG_PA_PMU_PM, FALSE);
    pGPIOReg  = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
#ifdef    SLEEP_AGING_TEST
    pRTCReg   = (RTC_REG *)OALPAtoVA(BASE_REG_PA_RTC, FALSE);
#endif

    g_LastWakeupStatus = pPMUPMReg->STATUS_REG.WAKEUP_STAT;
    
    switch(g_LastWakeupStatus)
    {
        case EINT_WAKEUP_STAT:                        // External Interrupt
            if (Get_EXTINT(pGPIOReg, EINT_POWER_BUTTON))    // Power Button : GPH3[7] = EINT31
            {
                Clear_EXTINT(pGPIOReg, EINT_POWER_BUTTON);
                g_oalWakeSource = SYSWAKE_POWER_BUTTON; // OEMWAKE_EINT11;
            }
			else if (Get_EXTINT(pGPIOReg, EXT_INT_1))    // Power Button : GPH0[1] = EINT1
			{
				Clear_EXTINT(pGPIOReg, EXT_INT_1);
				g_oalWakeSource = SYSWAKE_POWER_BUTTON; // OEMWAKE_EINT11;

			}
			else if (Get_EXTINT(pGPIOReg, EXT_INT_2))    // Power Button : GPH0[2] = EINT2
			{
				Clear_EXTINT(pGPIOReg, EXT_INT_2);
				g_oalWakeSource = SYSWAKE_POWER_BUTTON; // OEMWAKE_EINT11;

			}else if (Get_EXTINT(pGPIOReg, EXT_INT_3))    // Power Button : GPH0[3] = EINT3
			{
				Clear_EXTINT(pGPIOReg, EXT_INT_3);
				g_oalWakeSource = SYSWAKE_POWER_BUTTON; // OEMWAKE_EINT11;

			}			
            else
            {
                // TODO: To Be implemented...
                g_oalWakeSource = SYSWAKE_UNKNOWN;
            }
            break;
            
        case RTC_ALARM_WAKEUP_STAT:               // RTC Alarm
            g_oalWakeSource = OEMWAKE_RTC_ALARM;
#ifdef    SLEEP_AGING_TEST            
            // Disable the RTC Alarm
            pRTCReg->RTCALM = 0x0;

            // Clear RTC Alarm Interrupt Pending
            pRTCReg->INTP |= (1<<1);
#endif
            break;
            
        case RTC_TICK_WAKEUP_STAT:                // RTC Tick
            g_oalWakeSource = OEMWAKE_RTC_TICK;
            
#ifdef    SLEEP_AGING_TEST
            pRTCReg->RTCCON &= ~(1<<8);         // Tick Timer Disable
            pRTCReg->INTP = 0x1;                // Clear RTC Tick Interrupt Pending
#endif
            break;

        case TS_WAKEUP_STAT:                     // TS
            g_oalWakeSource = OEMWAKE_TS;
            break;
            
        case KEY_WAKEUP_STAT:                     // Keypad
            g_oalWakeSource = OEMWAKE_KEYPAD;
            break;
        case MODEM_WAKEUP_STAT:                   // MSM
            g_oalWakeSource = OEMWAKE_MSM;
            break;
            
        case MMC0_WAKEUP_STAT:                      
            g_oalWakeSource = OEMWAKE_MMC0;
            break;

        case MMC1_WAKEUP_STAT:                      
            g_oalWakeSource = OEMWAKE_MMC1;
            break;

        case MMC2_WAKEUP_STAT:                      
            g_oalWakeSource = OEMWAKE_MMC2;
            break;

        case MMC3_WAKEUP_STAT:                      
            g_oalWakeSource = OEMWAKE_MMC3;
            break;            
            
        case I2S_WAKEUP_STAT:
            g_oalWakeSource = OEMWAKE_I2S;
            break;

        case ST_WAKEUP_STAT:
            g_oalWakeSource = OEMWAKE_ST;
            break;

        case HDMICEC_WAKEUP_STAT:
            g_oalWakeSource = OEMWAKE_HDMICEC;
            break;
            
        default:        // Unknown or Multiple Wakeup Source ???
            g_oalWakeSource = SYSWAKE_UNKNOWN;
            break;
            
    }

    //---------------------------------------------------------------------
    // Clear All Wake Up Status bits
    // : This is cleared by writing 1.
    pPMUPMReg->STATUS_REG.WAKEUP_STAT = BP_WAKEUP_STAT_ALL_MASK;
    
    // EINT_MASK in SysCon Also Effective in Normal State
    // Unmask all bit for External Interrupt at Normal Mode
    pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK &= ~(BP_EINT_WAKEUP_ALL_MASK);

}

static BOOL CheckBypassSleep(void)
{
    volatile GPIO_REG *pGPIOReg;

    OALMSG(OAL_INFO, (L"[OEM] ++CheckBypassSleep()\r\n"));

    pGPIOReg = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);


#if 1 /// added by terry for  wake up test 2012.07.18

//	Set_PinFunction(pGPIOReg, GPH01_EXT_INT_1);
	Set_PinFunction(pGPIOReg, GPH02_EXT_INT_2);  // key sw5
	Set_PinFunction(pGPIOReg, GPH03_EXT_INT_3);  // key sw6

	return FALSE; 
#endif




    //OALMSG(TRUE, (L"[OEM] LED6 : %d \r\n", Get_PinData(pGPIOReg, LED6)));
    if(Get_PinData(pGPIOReg, LED6)){
        OALMSG(TRUE, (L"[OEM] DETECT! Bypass Sleep mode \r\n"));
        g_oalWakeSource = OEMWAKE_BYPASS;
        return TRUE;
    }
    OALMSG(OAL_INFO, (L"[OEM] --CheckBypassSleep() \r\n"));
    return FALSE;
}

static BOOL SetEarlyWakeup(void)
{
    volatile PMU_PM_REG *pPMUPMReg;
    volatile PMU_MISC_REG *pPMUMiscReg; 
    volatile VIC_REG *pVIC0Reg;
    volatile VIC_REG *pVIC1Reg;
    volatile VIC_REG *pVIC2Reg;
    volatile VIC_REG *pVIC3Reg;
    volatile GPIO_REG *pGPIOReg;
    DWORD dwWakeMask;
    DWORD dwEINTWakeMask;
    BOOL   bBypass=FALSE;
    BOOL   bPending=FALSE;
    BOOL    bRet=FALSE;
    
    OALMSG(OAL_INFO, (L"[OEM] ++SetEarlyWakeup()\r\n"));
    
    pPMUPMReg = (PMU_PM_REG *)OALPAtoVA(BASE_REG_PA_PMU_PM, FALSE);
    pPMUMiscReg = (PMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_PMU_MISC, FALSE);
    pVIC0Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC0, FALSE);
    pVIC1Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC1, FALSE);
    pVIC2Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC2, FALSE);
    pVIC3Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC3, FALSE);
    pGPIOReg = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);

    dwWakeMask = pPMUPMReg->PWR_CONF.WAKEUP_MASK;
    dwEINTWakeMask = pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK;
        
    // 1. Check Pending register with Wakeup Mask register
    // If Wakeup source interrupt is generated in here, 
    // bypass entering sleep mode and wakeup system right now.

    // Check WakeUp Source - Keypad 
    if( (!(dwWakeMask & (1<<BP_KEYIF_WAKEUP_MASK))) && (pVIC2Reg->VICRAWINTR & (1<<(PHYIRQ_KEYPAD-VIC2_BIT_OFFSET))))
    {
        bBypass=TRUE;
        g_oalWakeSource = OEMWAKE_KEYPAD;
    }

    // Check WakeUp Source - HDMICEC
    if( (!(dwWakeMask & (1<<BP_HDMICEC_WAKEUP_MASK))) && (pVIC3Reg->VICRAWINTR & (1<<(PHYIRQ_CEC-VIC3_BIT_OFFSET))))
    {
        bBypass=TRUE;
        g_oalWakeSource = OEMWAKE_HDMICEC;
    }

    // Check WakeUp Source - RTC ALARM
    if( (!(dwWakeMask & (1<<BP_RTC_ALARM_WAKEUP_MASK))) && (pVIC0Reg->VICRAWINTR & (1<<PHYIRQ_RTC_ALARM)))
    {
        bBypass=TRUE;
        g_oalWakeSource = OEMWAKE_RTC_ALARM;
    }

    // Check WakeUp Source - RTC Tick
    if( (!(dwWakeMask & (1<<BP_RTC_TICK_WAKEUP_MASK))) && (pVIC0Reg->VICRAWINTR & (1<<PHYIRQ_RTC_TIC)))
    {
        bBypass=TRUE;
        g_oalWakeSource = OEMWAKE_RTC_TICK;
    }
    
    // Check WakeUp Source - EINT0~15
    if((pVIC0Reg->VICRAWINTR & 0xffff) & ~(dwEINTWakeMask & 0xffff))
    {
        g_oalWakeSource = SYSWAKE_UNKNOWN;
    }

    // Check WakeUp Source - EINT16~31
    if(pVIC0Reg->VICRAWINTR & (1<<PHYIRQ_EINT16_31)){
        DWORD dwEintMask;
        
        dwEintMask = ~((dwEINTWakeMask << BP_EINT16_WAKEUP_MASK) & 0xff); // EINT16~23
        if((pGPIOReg->EINTPND.EXT_INT2_PEND&0xff) && dwEintMask)
        {
            bBypass=TRUE;
            g_oalWakeSource = SYSWAKE_UNKNOWN;
        }
        dwEintMask = ~((dwEINTWakeMask << BP_EINT24_WAKEUP_MASK) & 0xff); // EINT24~31
        if((pGPIOReg->EINTPND.EXT_INT3_PEND&0xff) && dwEintMask)
        {
            bBypass=TRUE;
            if((pGPIOReg->EINTPND.EXT_INT3_PEND&0xff)==0x80)    // EINT31: Power Button
                g_oalWakeSource = SYSWAKE_POWER_BUTTON;
            else
                g_oalWakeSource = SYSWAKE_UNKNOWN;
        }            
    }

    if(bBypass){

        // Here is interrupt of wakeup source, so wake up system right now. 
        
        //---------------------------------------------------------------------
        // Clear All Wake Up Status bits
        // : This is cleared by writing 1.
        pPMUPMReg->STATUS_REG.WAKEUP_STAT = BP_WAKEUP_STAT_ALL_MASK;
        
        // EINT_MASK in SysCon Also Effective in Normal State
        // Unmask all bit for External Interrupt at Normal Mode
        pPMUPMReg->PWR_CONF.EINT_WAKEUP_MASK &= ~(BP_EINT_WAKEUP_ALL_MASK);  
        
        bRet = TRUE;
    }
    else{
        
        // 2. Clear Pending Registers
        // Clear Vector Address Register
        pVIC0Reg->VICADDRESS = 0x0;
        pVIC1Reg->VICADDRESS = 0x0;
        pVIC2Reg->VICADDRESS = 0x0;
        pVIC3Reg->VICADDRESS = 0x0;  

        // Clear External interrupt
        pGPIOReg->EINTPND.EXT_INT0_PEND = 0xff;
        pGPIOReg->EINTPND.EXT_INT1_PEND = 0xff;
        pGPIOReg->EINTPND.EXT_INT2_PEND = 0xff;
        pGPIOReg->EINTPND.EXT_INT3_PEND = 0xff;

        // 3. set CFG_STANDBYWFI field of PWR_CFG to sleep mode.
        pPMUPMReg->PWR_CONF.PWR_CFG = (pPMUPMReg->PWR_CONF.PWR_CFG & ~(BW_CFG_STANDBYWFI<<BP_CFG_STANDBYWFI)) | (CFG_ENTER_SLEEP<<BP_CFG_STANDBYWFI); 

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

    OALMSG(OAL_INFO, (L"[OEM] --SetEarlyWakeup()\r\n"));        

    return bRet;
}


//------------------------------------------------------------------------------
//
// Function:     OEMPowerOff
//
// Description:  Called when the system is to transition to it's lowest  power mode (off)
//
//
//#pragma optimize ("",off)
void OEMPowerOff()
{
    volatile VIC_REG *pVIC0Reg;
    volatile VIC_REG *pVIC1Reg;
    volatile VIC_REG *pVIC2Reg;
    volatile VIC_REG *pVIC3Reg;
    volatile DMAC_REG *pMDMACReg;       
    volatile DMAC_REG *pPDMAC0Reg;
    volatile DMAC_REG *pPDMAC1Reg;
    volatile GPIO_REG *pGPIOReg;
    volatile CMU_CLK_REG *pCMUCLKReg;
#if (S5PV210_EVT==0)    
    volatile CMU_SYS_REG *pCMUSYSReg;
#endif
    volatile CMU_MISC_REG *pCMUMISCReg;
    volatile PMU_PM_REG *pPMUPMReg;
#ifdef RTC_TICK_ERROR_COMPENSATION    
    volatile RTC_REG *pRTCReg;
    volatile BSP_ARGS *pBSPArg;
#endif    

    OALMSG(TRUE, (L"[OEM] ++OEMPowerOff()\r\n"));

    //---------------------------------------------------------------------
    // Prepare Specific Actions for Sleep

    //BSPPowerOff();

    //---------------------------------------------------------------------
    // Prepare CPU Entering Sleep Mode


    //---------------------------------------------------------------------
    // Map SFR Address
    pGPIOReg = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
    pVIC0Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC0, FALSE);
    pVIC1Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC1, FALSE);
    pVIC2Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC2, FALSE);
    pVIC3Reg = (VIC_REG *)OALPAtoVA(BASE_REG_PA_VIC3, FALSE);
    pMDMACReg = (DMAC_REG*)OALPAtoVA(BASE_REG_PA_MDMA, FALSE);
    pPDMAC0Reg = (DMAC_REG*)OALPAtoVA(BASE_REG_PA_PDMA0, FALSE);
    pPDMAC1Reg = (DMAC_REG*)OALPAtoVA(BASE_REG_PA_PDMA1, FALSE);
    pCMUCLKReg = (CMU_CLK_REG *)OALPAtoVA(BASE_REG_PA_CMU_CLK, FALSE);
#if (S5PV210_EVT==0)    
    pCMUSYSReg = (CMU_SYS_REG *)OALPAtoVA(BASE_REG_PA_CMU_SYS, FALSE);
#endif
    pCMUMISCReg = (CMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_CMU_MISC, FALSE);
    pPMUPMReg = (PMU_PM_REG *)OALPAtoVA(BASE_REG_PA_PMU_PM, FALSE);
#ifdef RTC_TICK_ERROR_COMPENSATION  
    pRTCReg = (RTC_REG*)OALPAtoVA(BASE_REG_PA_RTC, FALSE);
    pBSPArg = (BSP_ARGS*)IMAGE_SHARE_ARGS_UA_START; 
#endif    

    //---------------------------------------------------------------------
    // Check bypass sleep mode
    if(CheckBypassSleep()){
        OALMSG(TRUE, (L"[OEM] Bypass entering sleep mode \r\n"));
        return;
    }

    //---------------------------------------------------------------------
    // Save VIC Registers
    SaveState_VIC((void *)pVIC0Reg, (void *)pVIC1Reg, (void *)pVIC2Reg, (void *)pVIC3Reg, g_aSleepSave_VIC);

    // Disable All Interrupt
    pVIC0Reg->VICINTENCLEAR = 0xFFFFFFFF;
    pVIC1Reg->VICINTENCLEAR = 0xFFFFFFFF;
    pVIC2Reg->VICINTENCLEAR = 0xFFFFFFFF;
    pVIC3Reg->VICINTENCLEAR = 0xFFFFFFFF;
    pVIC0Reg->VICSOFTINTCLEAR = 0xFFFFFFFF;
    pVIC1Reg->VICSOFTINTCLEAR = 0xFFFFFFFF;
    pVIC2Reg->VICSOFTINTCLEAR = 0xFFFFFFFF;
    pVIC3Reg->VICSOFTINTCLEAR = 0xFFFFFFFF;
	
//add by jerry
//	pVIC3Reg->VICINTENCLEAR = 0xFFFFF9FF;
//	pVIC3Reg->VICSOFTINTCLEAR = 0xFFFFF9FF;
//	pVIC3Reg->VICIRQSTATUS |= (0x3<<9);
//------------------------------	

    //---------------------------------------------------------------------
    // Wake Up Source Configuration
    SetWakeupSource();

    //---------------------------------------------------------------------
    // Set EarlyWaekup 
    if(SetEarlyWakeup()){
        OALMSG(TRUE, (L"[OEM] This is early-wakeup, wakeup right now \r\n"));
        
        //---------------------------------------------------------------------
        // Restore VIC Registers
        RestoreState_VIC((void *)pVIC0Reg, (void *)pVIC1Reg, (void *)pVIC2Reg, (void *)pVIC3Reg, g_aSleepSave_VIC);
        return;    
    }
   
    //---------------------------------------------------------------------
    // Save DMA Register      
    SaveState_DMACon((void *)pPDMAC0Reg, (void *)pPDMAC1Reg, (void *)pMDMACReg, g_aSleepSave_DMACon);

    //---------------------------------------------------------------------
    // Save GPIO Register
    SaveState_GPIO((void *)pGPIOReg, g_aSleepSave_GPIO);

    //---------------------------------------------------------------------
    // Save CMU Register
#if (S5PV210_EVT==0)    
    SaveState_CMU((void *)pCMUCLKReg, (void *)pCMUSYSReg, (void *)pCMUMISCReg, g_aSleepSave_SysCon);
#else
    SaveState_CMU((void *)pCMUCLKReg, (void *)pCMUMISCReg, g_aSleepSave_SysCon);
#endif

    //---------------------------------------------------------------------
    // Save PMU Register
    SaveState_PMU((void *)pPMUPMReg, g_aSleepSave_PMU);
    
#ifdef RTC_TICK_ERROR_COMPENSATION 
    pRTCReg->RTCCON |= 1<<0;
    pRTCReg->RTCCON &= ~(1<<8);
    pRTCReg->RTCCON &= ~(1<<0);
    pRTCReg->INTP = (pRTCReg->INTP & ~(0x3)) |(1<<0); 
#endif

    CPUSleepMode();                                // Now in Sleep

    //---------------------------------------------------------------------
    // CPU Wake Up from Sleep Mode
    //---------------------------------------------------------------------

    //---------------------------------------------------------------------
    // Wake Up Source Determine
    GetWakeupSource();

#ifdef RTC_TICK_ERROR_COMPENSATION 
    pBSPArg->bTickCountInit = TRUE;
#endif

    //---------------------------------------------------------------------
    // Restore PMU Register
    RestoreState_PMU((void *)pPMUPMReg, g_aSleepSave_PMU);

    //---------------------------------------------------------------------
    // Restore CMU Register
#if (S5PV210_EVT==0)    
    RestoreState_CMU((void *)pCMUCLKReg, (void *)pCMUSYSReg, (void *)pCMUMISCReg, g_aSleepSave_SysCon);
#else
    RestoreState_CMU((void *)pCMUCLKReg, (void *)pCMUMISCReg, g_aSleepSave_SysCon);
#endif
    //---------------------------------------------------------------------
    // Restore GPIO Register
    RestoreState_GPIO((void *)pGPIOReg, g_aSleepSave_GPIO);

    //---------------------------------------------------------------------
    // Restore DMAC Registers
    // : Have to Check about PL330
    RestoreState_DMACon((void *)pPDMAC0Reg, (void *)pPDMAC1Reg, (void *)pMDMACReg, g_aSleepSave_DMACon);

    //---------------------------------------------------------------------
    // Restore VIC Registers
    RestoreState_VIC((void *)pVIC0Reg, (void *)pVIC1Reg, (void *)pVIC2Reg, (void *)pVIC3Reg, g_aSleepSave_VIC);

    //---------------------------------------------------------------------
    // UART Debug Port Initialize
    OEMInitDebugSerial();

    //---------------------------------------------------------------------
    // Enable Branch Prediction on CP15
    System_EnableBP();

    //---------------------------------------------------------------------
    // Enable IRQ Interrupt on CP15
    //System_EnableIRQ();

    //---------------------------------------------------------------------
    // Enable FIQ Interrupt on CP15
    //System_EnableFIQ();

    //---------------------------------------------------------------------
    if (g_oalWakeSource == SYSWAKE_UNKNOWN)
    {
        OALMSG(TRUE, (L"[OEM:ERR] OEMPowerOff() : SYSWAKE_UNKNOWN , WAKEUP_STAT = 0x%08x", g_LastWakeupStatus));
    }

    //---------------------------------------------------------------------
    // Initialize System Timer
    InitSystemTimer(g_oalTimer.msecPerSysTick*g_oalTimer.countsPerMSec);

    OALMSG(TRUE, (L"[OEM] --OEMPowerOff()\r\n"));

}
//#pragma optimize ("",on)

