bb072c3cf2
Replace sysdev classes and struct sys_device objects used for "core" power management by Samsung platforms with struct syscore_ops objects that are simpler. This generally reduces the code size and the kernel memory footprint. It also is necessary for removing sysdevs entirely from the kernel in the future. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Greg Kroah-Hartman <gregkh@suse.de> Acked-by: Kukjin Kim <kgene.kim@samsung.com>
429 lines
14 KiB
C
429 lines
14 KiB
C
/* 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>
|
|
#include <linux/syscore_ops.h>
|
|
#include <linux/io.h>
|
|
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/hardware/cache-l2x0.h>
|
|
|
|
#include <plat/cpu.h>
|
|
#include <plat/pm.h>
|
|
|
|
#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>
|
|
|
|
static struct sleep_save exynos4_sleep[] = {
|
|
{ .reg = S5P_ARM_CORE0_LOWPWR , .val = 0x2, },
|
|
{ .reg = S5P_DIS_IRQ_CORE0 , .val = 0x0, },
|
|
{ .reg = S5P_DIS_IRQ_CENTRAL0 , .val = 0x0, },
|
|
{ .reg = S5P_ARM_CORE1_LOWPWR , .val = 0x2, },
|
|
{ .reg = S5P_DIS_IRQ_CORE1 , .val = 0x0, },
|
|
{ .reg = S5P_DIS_IRQ_CENTRAL1 , .val = 0x0, },
|
|
{ .reg = S5P_ARM_COMMON_LOWPWR , .val = 0x2, },
|
|
{ .reg = S5P_L2_0_LOWPWR , .val = 0x3, },
|
|
{ .reg = S5P_L2_1_LOWPWR , .val = 0x3, },
|
|
{ .reg = S5P_CMU_ACLKSTOP_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_SCLKSTOP_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_APLL_SYSCLK_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_MPLL_SYSCLK_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_VPLL_SYSCLK_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_EPLL_SYSCLK_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_GPSALIVE_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_CAM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_TV_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_MFC_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_G3D_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_LCD0_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_LCD1_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_MAUDIO_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_CLKSTOP_GPS_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_CAM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_TV_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_MFC_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_G3D_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_LCD0_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_LCD1_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_MAUDIO_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CMU_RESET_GPS_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_TOP_BUS_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_TOP_RETENTION_LOWPWR , .val = 0x1, },
|
|
{ .reg = S5P_TOP_PWR_LOWPWR , .val = 0x3, },
|
|
{ .reg = S5P_LOGIC_RESET_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_ONENAND_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_MODIMIF_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_G2D_ACP_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_USBOTG_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_HSMMC_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CSSYS_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_SECSS_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PCIE_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_SATA_MEM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_DRAM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_MAUDIO_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_GPIO_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_UART_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_MMCA_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_MMCB_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_EBIA_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_EBIB_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_ISOLATION_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_PAD_RETENTION_ALV_SEL_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_XUSBXTI_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_XXTI_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_EXT_REGULATOR_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_GPIO_MODE_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_GPIO_MODE_MAUDIO_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_CAM_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_TV_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_MFC_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_G3D_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_LCD0_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_LCD1_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_MAUDIO_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_GPS_LOWPWR , .val = 0x0, },
|
|
{ .reg = S5P_GPS_ALIVE_LOWPWR , .val = 0x0, },
|
|
};
|
|
|
|
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, },
|
|
};
|
|
|
|
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_EPLL_CON0),
|
|
SAVE_ITEM(S5P_EPLL_CON1),
|
|
SAVE_ITEM(S5P_VPLL_CON0),
|
|
SAVE_ITEM(S5P_VPLL_CON1),
|
|
SAVE_ITEM(S5P_CLKSRC_TOP0),
|
|
SAVE_ITEM(S5P_CLKSRC_TOP1),
|
|
SAVE_ITEM(S5P_CLKSRC_CAM),
|
|
SAVE_ITEM(S5P_CLKSRC_MFC),
|
|
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),
|
|
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),
|
|
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),
|
|
SAVE_ITEM(S5P_CLKGATE_SCLKCPU),
|
|
SAVE_ITEM(S5P_CLKGATE_IP_CPU),
|
|
/* 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),
|
|
};
|
|
|
|
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),
|
|
};
|
|
|
|
void exynos4_cpu_suspend(void)
|
|
{
|
|
unsigned long tmp;
|
|
unsigned long mask = 0xFFFFFFFF;
|
|
|
|
/* 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);
|
|
|
|
/* Setting Central Sequence option Register */
|
|
|
|
tmp = __raw_readl(S5P_CENTRAL_SEQ_OPTION);
|
|
tmp &= ~(S5P_USE_MASK);
|
|
tmp |= S5P_USE_STANDBY_WFI0;
|
|
__raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
|
|
|
|
/* Clear all interrupt pending to avoid early wakeup */
|
|
|
|
__raw_writel(mask, (S5P_VA_GIC_DIST + 0x280));
|
|
__raw_writel(mask, (S5P_VA_GIC_DIST + 0x284));
|
|
__raw_writel(mask, (S5P_VA_GIC_DIST + 0x288));
|
|
|
|
/* Disable all interrupt */
|
|
|
|
__raw_writel(0x0, (S5P_VA_GIC_CPU + 0x000));
|
|
__raw_writel(0x0, (S5P_VA_GIC_DIST + 0x000));
|
|
__raw_writel(mask, (S5P_VA_GIC_DIST + 0x184));
|
|
__raw_writel(mask, (S5P_VA_GIC_DIST + 0x188));
|
|
|
|
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));
|
|
|
|
tmp = __raw_readl(S5P_INFORM1);
|
|
|
|
/* Set value of power down register for sleep mode */
|
|
|
|
s3c_pm_do_restore_core(exynos4_sleep, ARRAY_SIZE(exynos4_sleep));
|
|
__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();
|
|
}
|
|
|
|
static struct sysdev_driver exynos4_pm_driver = {
|
|
.add = exynos4_pm_add,
|
|
};
|
|
|
|
static __init int exynos4_pm_drvinit(void)
|
|
{
|
|
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);
|
|
|
|
return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver);
|
|
}
|
|
arch_initcall(exynos4_pm_drvinit);
|
|
|
|
static void exynos4_pm_resume(void)
|
|
{
|
|
/* 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));
|
|
|
|
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
|
|
}
|
|
|
|
static struct syscore_ops exynos4_pm_syscore_ops = {
|
|
.resume = exynos4_pm_resume,
|
|
};
|
|
|
|
static __init int exynos4_pm_syscore_init(void)
|
|
{
|
|
register_syscore_ops(&exynos4_pm_syscore_ops);
|
|
return 0;
|
|
}
|
|
arch_initcall(exynos4_pm_syscore_init);
|