2011-03-10 07:33:59 +03:00
/* linux/arch/arm/mach-exynos4/pm.c
*
* Copyright ( c ) 2011 Samsung Electronics Co . , Ltd .
* http : //www.samsung.com
*
* EXYNOS4210 - Power Management support
*
* Based on arch / arm / mach - s3c2410 / pm . c
* Copyright ( c ) 2006 Simtec Electronics
* Ben Dooks < ben @ simtec . co . uk >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/init.h>
# include <linux/suspend.h>
2011-04-23 00:03:21 +04:00
# include <linux/syscore_ops.h>
2011-03-10 07:33:59 +03:00
# include <linux/io.h>
2011-07-18 14:25:13 +04:00
# include <linux/err.h>
# include <linux/clk.h>
2011-03-10 07:33:59 +03:00
# include <asm/cacheflush.h>
# include <asm/hardware/cache-l2x0.h>
# include <plat/cpu.h>
# include <plat/pm.h>
2011-07-18 14:25:13 +04:00
# include <plat/pll.h>
2011-07-21 06:25:23 +04:00
# include <plat/regs-srom.h>
2011-03-10 07:33:59 +03:00
# include <mach/regs-irq.h>
# include <mach/regs-gpio.h>
# include <mach/regs-clock.h>
# include <mach/regs-pmu.h>
# include <mach/pm-core.h>
2011-07-18 14:21:27 +04:00
# include <mach/pmu.h>
2011-03-10 07:33:59 +03:00
static struct sleep_save exynos4_set_clksrc [ ] = {
{ . reg = S5P_CLKSRC_MASK_TOP , . val = 0x00000001 , } ,
{ . reg = S5P_CLKSRC_MASK_CAM , . val = 0x11111111 , } ,
{ . reg = S5P_CLKSRC_MASK_TV , . val = 0x00000111 , } ,
{ . reg = S5P_CLKSRC_MASK_LCD0 , . val = 0x00001111 , } ,
{ . reg = S5P_CLKSRC_MASK_LCD1 , . val = 0x00001111 , } ,
{ . reg = S5P_CLKSRC_MASK_MAUDIO , . val = 0x00000001 , } ,
{ . reg = S5P_CLKSRC_MASK_FSYS , . val = 0x01011111 , } ,
{ . reg = S5P_CLKSRC_MASK_PERIL0 , . val = 0x01111111 , } ,
{ . reg = S5P_CLKSRC_MASK_PERIL1 , . val = 0x01110111 , } ,
{ . reg = S5P_CLKSRC_MASK_DMC , . val = 0x00010000 , } ,
} ;
2011-07-18 14:25:13 +04:00
static struct sleep_save exynos4_epll_save [ ] = {
SAVE_ITEM ( S5P_EPLL_CON0 ) ,
SAVE_ITEM ( S5P_EPLL_CON1 ) ,
} ;
static struct sleep_save exynos4_vpll_save [ ] = {
SAVE_ITEM ( S5P_VPLL_CON0 ) ,
SAVE_ITEM ( S5P_VPLL_CON1 ) ,
} ;
2011-03-10 07:33:59 +03:00
static struct sleep_save exynos4_core_save [ ] = {
/* CMU side */
SAVE_ITEM ( S5P_CLKDIV_LEFTBUS ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_LEFTBUS ) ,
SAVE_ITEM ( S5P_CLKDIV_RIGHTBUS ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_RIGHTBUS ) ,
SAVE_ITEM ( S5P_CLKSRC_TOP0 ) ,
SAVE_ITEM ( S5P_CLKSRC_TOP1 ) ,
SAVE_ITEM ( S5P_CLKSRC_CAM ) ,
2011-07-21 06:25:23 +04:00
SAVE_ITEM ( S5P_CLKSRC_TV ) ,
2011-03-10 07:33:59 +03:00
SAVE_ITEM ( S5P_CLKSRC_MFC ) ,
2011-07-21 06:25:23 +04:00
SAVE_ITEM ( S5P_CLKSRC_G3D ) ,
2011-03-10 07:33:59 +03:00
SAVE_ITEM ( S5P_CLKSRC_IMAGE ) ,
SAVE_ITEM ( S5P_CLKSRC_LCD0 ) ,
SAVE_ITEM ( S5P_CLKSRC_LCD1 ) ,
SAVE_ITEM ( S5P_CLKSRC_MAUDIO ) ,
SAVE_ITEM ( S5P_CLKSRC_FSYS ) ,
SAVE_ITEM ( S5P_CLKSRC_PERIL0 ) ,
SAVE_ITEM ( S5P_CLKSRC_PERIL1 ) ,
SAVE_ITEM ( S5P_CLKDIV_CAM ) ,
SAVE_ITEM ( S5P_CLKDIV_TV ) ,
SAVE_ITEM ( S5P_CLKDIV_MFC ) ,
SAVE_ITEM ( S5P_CLKDIV_G3D ) ,
SAVE_ITEM ( S5P_CLKDIV_IMAGE ) ,
SAVE_ITEM ( S5P_CLKDIV_LCD0 ) ,
SAVE_ITEM ( S5P_CLKDIV_LCD1 ) ,
SAVE_ITEM ( S5P_CLKDIV_MAUDIO ) ,
SAVE_ITEM ( S5P_CLKDIV_FSYS0 ) ,
SAVE_ITEM ( S5P_CLKDIV_FSYS1 ) ,
SAVE_ITEM ( S5P_CLKDIV_FSYS2 ) ,
SAVE_ITEM ( S5P_CLKDIV_FSYS3 ) ,
SAVE_ITEM ( S5P_CLKDIV_PERIL0 ) ,
SAVE_ITEM ( S5P_CLKDIV_PERIL1 ) ,
SAVE_ITEM ( S5P_CLKDIV_PERIL2 ) ,
SAVE_ITEM ( S5P_CLKDIV_PERIL3 ) ,
SAVE_ITEM ( S5P_CLKDIV_PERIL4 ) ,
SAVE_ITEM ( S5P_CLKDIV_PERIL5 ) ,
SAVE_ITEM ( S5P_CLKDIV_TOP ) ,
2011-07-21 06:25:23 +04:00
SAVE_ITEM ( S5P_CLKSRC_MASK_TOP ) ,
2011-03-10 07:33:59 +03:00
SAVE_ITEM ( S5P_CLKSRC_MASK_CAM ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_TV ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_LCD0 ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_LCD1 ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_MAUDIO ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_FSYS ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_PERIL0 ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_PERIL1 ) ,
2011-07-21 06:25:23 +04:00
SAVE_ITEM ( S5P_CLKDIV2_RATIO ) ,
2011-03-10 07:33:59 +03:00
SAVE_ITEM ( S5P_CLKGATE_SCLKCAM ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_CAM ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_TV ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_MFC ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_G3D ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_IMAGE ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_LCD0 ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_LCD1 ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_FSYS ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_GPS ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_PERIL ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_PERIR ) ,
SAVE_ITEM ( S5P_CLKGATE_BLOCK ) ,
SAVE_ITEM ( S5P_CLKSRC_MASK_DMC ) ,
SAVE_ITEM ( S5P_CLKSRC_DMC ) ,
SAVE_ITEM ( S5P_CLKDIV_DMC0 ) ,
SAVE_ITEM ( S5P_CLKDIV_DMC1 ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_DMC ) ,
SAVE_ITEM ( S5P_CLKSRC_CPU ) ,
SAVE_ITEM ( S5P_CLKDIV_CPU ) ,
2011-07-21 06:25:23 +04:00
SAVE_ITEM ( S5P_CLKDIV_CPU + 0x4 ) ,
2011-03-10 07:33:59 +03:00
SAVE_ITEM ( S5P_CLKGATE_SCLKCPU ) ,
SAVE_ITEM ( S5P_CLKGATE_IP_CPU ) ,
2011-07-21 06:25:23 +04:00
2011-03-10 07:33:59 +03:00
/* GIC side */
SAVE_ITEM ( S5P_VA_GIC_CPU + 0x000 ) ,
SAVE_ITEM ( S5P_VA_GIC_CPU + 0x004 ) ,
SAVE_ITEM ( S5P_VA_GIC_CPU + 0x008 ) ,
SAVE_ITEM ( S5P_VA_GIC_CPU + 0x00C ) ,
SAVE_ITEM ( S5P_VA_GIC_CPU + 0x014 ) ,
SAVE_ITEM ( S5P_VA_GIC_CPU + 0x018 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x000 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x004 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x100 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x104 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x108 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x300 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x304 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x308 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x400 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x404 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x408 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x40C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x410 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x414 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x418 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x41C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x420 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x424 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x428 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x42C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x430 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x434 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x438 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x43C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x440 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x444 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x448 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x44C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x450 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x454 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x458 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x45C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x800 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x804 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x808 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x80C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x810 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x814 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x818 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x81C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x820 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x824 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x828 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x82C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x830 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x834 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x838 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x83C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x840 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x844 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x848 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x84C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x850 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x854 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x858 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0x85C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0xC00 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0xC04 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0xC08 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0xC0C ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0xC10 ) ,
SAVE_ITEM ( S5P_VA_GIC_DIST + 0xC14 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x000 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x010 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x020 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x030 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x040 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x050 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x060 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x070 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x080 ) ,
SAVE_ITEM ( S5P_VA_COMBINER_BASE + 0x090 ) ,
2011-07-21 06:25:23 +04:00
/* SROM side */
SAVE_ITEM ( S5P_SROM_BW ) ,
SAVE_ITEM ( S5P_SROM_BC0 ) ,
SAVE_ITEM ( S5P_SROM_BC1 ) ,
SAVE_ITEM ( S5P_SROM_BC2 ) ,
SAVE_ITEM ( S5P_SROM_BC3 ) ,
2011-03-10 07:33:59 +03:00
} ;
static struct sleep_save exynos4_l2cc_save [ ] = {
SAVE_ITEM ( S5P_VA_L2CC + L2X0_TAG_LATENCY_CTRL ) ,
SAVE_ITEM ( S5P_VA_L2CC + L2X0_DATA_LATENCY_CTRL ) ,
SAVE_ITEM ( S5P_VA_L2CC + L2X0_PREFETCH_CTRL ) ,
SAVE_ITEM ( S5P_VA_L2CC + L2X0_POWER_CTRL ) ,
SAVE_ITEM ( S5P_VA_L2CC + L2X0_AUX_CTRL ) ,
} ;
2011-07-18 14:25:03 +04:00
/* For Cortex-A9 Diagnostic and Power control register */
static unsigned int save_arm_register [ 2 ] ;
2011-07-02 12:54:01 +04:00
static int exynos4_cpu_suspend ( unsigned long arg )
2011-03-10 07:33:59 +03:00
{
outer_flush_all ( ) ;
/* issue the standby signal into the pm unit. */
cpu_do_idle ( ) ;
/* we should never get past here */
panic ( " sleep resumed to originator? " ) ;
}
static void exynos4_pm_prepare ( void )
{
u32 tmp ;
s3c_pm_do_save ( exynos4_core_save , ARRAY_SIZE ( exynos4_core_save ) ) ;
s3c_pm_do_save ( exynos4_l2cc_save , ARRAY_SIZE ( exynos4_l2cc_save ) ) ;
2011-07-18 14:25:13 +04:00
s3c_pm_do_save ( exynos4_epll_save , ARRAY_SIZE ( exynos4_epll_save ) ) ;
s3c_pm_do_save ( exynos4_vpll_save , ARRAY_SIZE ( exynos4_vpll_save ) ) ;
2011-03-10 07:33:59 +03:00
tmp = __raw_readl ( S5P_INFORM1 ) ;
/* Set value of power down register for sleep mode */
2011-07-18 14:21:27 +04:00
exynos4_sys_powerdown_conf ( SYS_SLEEP ) ;
2011-03-10 07:33:59 +03:00
__raw_writel ( S5P_CHECK_SLEEP , S5P_INFORM1 ) ;
/* ensure at least INFORM0 has the resume address */
__raw_writel ( virt_to_phys ( s3c_cpu_resume ) , S5P_INFORM0 ) ;
/* Before enter central sequence mode, clock src register have to set */
s3c_pm_do_restore_core ( exynos4_set_clksrc , ARRAY_SIZE ( exynos4_set_clksrc ) ) ;
}
static int exynos4_pm_add ( struct sys_device * sysdev )
{
pm_cpu_prep = exynos4_pm_prepare ;
pm_cpu_sleep = exynos4_cpu_suspend ;
return 0 ;
}
/* This function copy from linux/arch/arm/kernel/smp_scu.c */
void exynos4_scu_enable ( void __iomem * scu_base )
{
u32 scu_ctrl ;
scu_ctrl = __raw_readl ( scu_base ) ;
/* already enabled? */
if ( scu_ctrl & 1 )
return ;
scu_ctrl | = 1 ;
__raw_writel ( scu_ctrl , scu_base ) ;
/*
* Ensure that the data accessed by CPU0 before the SCU was
* initialised is visible to the other CPUs .
*/
flush_cache_all ( ) ;
}
2011-07-18 14:25:13 +04:00
static unsigned long pll_base_rate ;
static void exynos4_restore_pll ( void )
{
unsigned long pll_con , locktime , lockcnt ;
unsigned long pll_in_rate ;
unsigned int p_div , epll_wait = 0 , vpll_wait = 0 ;
if ( pll_base_rate = = 0 )
return ;
pll_in_rate = pll_base_rate ;
/* EPLL */
pll_con = exynos4_epll_save [ 0 ] . val ;
if ( pll_con & ( 1 < < 31 ) ) {
pll_con & = ( PLL46XX_PDIV_MASK < < PLL46XX_PDIV_SHIFT ) ;
p_div = ( pll_con > > PLL46XX_PDIV_SHIFT ) ;
pll_in_rate / = 1000000 ;
locktime = ( 3000 / pll_in_rate ) * p_div ;
lockcnt = locktime * 10000 / ( 10000 / pll_in_rate ) ;
__raw_writel ( lockcnt , S5P_EPLL_LOCK ) ;
s3c_pm_do_restore_core ( exynos4_epll_save ,
ARRAY_SIZE ( exynos4_epll_save ) ) ;
epll_wait = 1 ;
}
pll_in_rate = pll_base_rate ;
/* VPLL */
pll_con = exynos4_vpll_save [ 0 ] . val ;
if ( pll_con & ( 1 < < 31 ) ) {
pll_in_rate / = 1000000 ;
/* 750us */
locktime = 750 ;
lockcnt = locktime * 10000 / ( 10000 / pll_in_rate ) ;
__raw_writel ( lockcnt , S5P_VPLL_LOCK ) ;
s3c_pm_do_restore_core ( exynos4_vpll_save ,
ARRAY_SIZE ( exynos4_vpll_save ) ) ;
vpll_wait = 1 ;
}
/* Wait PLL locking */
do {
if ( epll_wait ) {
pll_con = __raw_readl ( S5P_EPLL_CON0 ) ;
if ( pll_con & ( 1 < < S5P_EPLLCON0_LOCKED_SHIFT ) )
epll_wait = 0 ;
}
if ( vpll_wait ) {
pll_con = __raw_readl ( S5P_VPLL_CON0 ) ;
if ( pll_con & ( 1 < < S5P_VPLLCON0_LOCKED_SHIFT ) )
vpll_wait = 0 ;
}
} while ( epll_wait | | vpll_wait ) ;
}
2011-04-23 00:03:21 +04:00
static struct sysdev_driver exynos4_pm_driver = {
. add = exynos4_pm_add ,
} ;
static __init int exynos4_pm_drvinit ( void )
{
2011-07-18 14:25:13 +04:00
struct clk * pll_base ;
2011-04-23 00:03:21 +04:00
unsigned int tmp ;
s3c_pm_init ( ) ;
/* All wakeup disable */
tmp = __raw_readl ( S5P_WAKEUP_MASK ) ;
tmp | = ( ( 0xFF < < 8 ) | ( 0x1F < < 1 ) ) ;
__raw_writel ( tmp , S5P_WAKEUP_MASK ) ;
2011-07-18 14:25:13 +04:00
pll_base = clk_get ( NULL , " xtal " ) ;
if ( ! IS_ERR ( pll_base ) ) {
pll_base_rate = clk_get_rate ( pll_base ) ;
clk_put ( pll_base ) ;
}
2011-04-23 00:03:21 +04:00
return sysdev_driver_register ( & exynos4_sysclass , & exynos4_pm_driver ) ;
}
arch_initcall ( exynos4_pm_drvinit ) ;
2011-07-18 14:21:41 +04:00
static int exynos4_pm_suspend ( void )
{
unsigned long tmp ;
/* Setting Central Sequence Register for power down mode */
tmp = __raw_readl ( S5P_CENTRAL_SEQ_CONFIGURATION ) ;
tmp & = ~ S5P_CENTRAL_LOWPWR_CFG ;
__raw_writel ( tmp , S5P_CENTRAL_SEQ_CONFIGURATION ) ;
2011-07-18 14:25:03 +04:00
/* Save Power control register */
asm ( " mrc p15, 0, %0, c15, c0, 0 "
: " =r " ( tmp ) : : " cc " ) ;
save_arm_register [ 0 ] = tmp ;
/* Save Diagnostic register */
asm ( " mrc p15, 0, %0, c15, c0, 1 "
: " =r " ( tmp ) : : " cc " ) ;
save_arm_register [ 1 ] = tmp ;
2011-07-18 14:21:41 +04:00
return 0 ;
}
2011-04-23 00:03:21 +04:00
static void exynos4_pm_resume ( void )
2011-03-10 07:33:59 +03:00
{
2011-07-18 14:21:34 +04:00
unsigned long tmp ;
/*
* If PMU failed while entering sleep mode , WFI will be
* ignored by PMU and then exiting cpu_do_idle ( ) .
* S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
* in this situation .
*/
tmp = __raw_readl ( S5P_CENTRAL_SEQ_CONFIGURATION ) ;
if ( ! ( tmp & S5P_CENTRAL_LOWPWR_CFG ) ) {
tmp | = S5P_CENTRAL_LOWPWR_CFG ;
__raw_writel ( tmp , S5P_CENTRAL_SEQ_CONFIGURATION ) ;
/* No need to perform below restore code */
goto early_wakeup ;
}
2011-07-18 14:25:03 +04:00
/* Restore Power control register */
tmp = save_arm_register [ 0 ] ;
asm volatile ( " mcr p15, 0, %0, c15, c0, 0 "
: : " r " ( tmp )
: " cc " ) ;
/* Restore Diagnostic register */
tmp = save_arm_register [ 1 ] ;
asm volatile ( " mcr p15, 0, %0, c15, c0, 1 "
: : " r " ( tmp )
: " cc " ) ;
2011-07-18 14:21:34 +04:00
2011-03-10 07:33:59 +03:00
/* For release retention */
__raw_writel ( ( 1 < < 28 ) , S5P_PAD_RET_MAUDIO_OPTION ) ;
__raw_writel ( ( 1 < < 28 ) , S5P_PAD_RET_GPIO_OPTION ) ;
__raw_writel ( ( 1 < < 28 ) , S5P_PAD_RET_UART_OPTION ) ;
__raw_writel ( ( 1 < < 28 ) , S5P_PAD_RET_MMCA_OPTION ) ;
__raw_writel ( ( 1 < < 28 ) , S5P_PAD_RET_MMCB_OPTION ) ;
__raw_writel ( ( 1 < < 28 ) , S5P_PAD_RET_EBIA_OPTION ) ;
__raw_writel ( ( 1 < < 28 ) , S5P_PAD_RET_EBIB_OPTION ) ;
s3c_pm_do_restore_core ( exynos4_core_save , ARRAY_SIZE ( exynos4_core_save ) ) ;
2011-07-18 14:25:13 +04:00
exynos4_restore_pll ( ) ;
2011-03-10 07:33:59 +03:00
exynos4_scu_enable ( S5P_VA_SCU ) ;
# ifdef CONFIG_CACHE_L2X0
s3c_pm_do_restore_core ( exynos4_l2cc_save , ARRAY_SIZE ( exynos4_l2cc_save ) ) ;
outer_inv_all ( ) ;
/* enable L2X0*/
writel_relaxed ( 1 , S5P_VA_L2CC + L2X0_CTRL ) ;
# endif
2011-07-18 14:21:34 +04:00
early_wakeup :
return ;
2011-03-10 07:33:59 +03:00
}
2011-04-23 00:03:21 +04:00
static struct syscore_ops exynos4_pm_syscore_ops = {
2011-07-18 14:21:41 +04:00
. suspend = exynos4_pm_suspend ,
2011-03-10 07:33:59 +03:00
. resume = exynos4_pm_resume ,
} ;
2011-04-23 00:03:21 +04:00
static __init int exynos4_pm_syscore_init ( void )
2011-03-10 07:33:59 +03:00
{
2011-04-23 00:03:21 +04:00
register_syscore_ops ( & exynos4_pm_syscore_ops ) ;
return 0 ;
2011-03-10 07:33:59 +03:00
}
2011-04-23 00:03:21 +04:00
arch_initcall ( exynos4_pm_syscore_init ) ;