diff options
Diffstat (limited to 'arch/arm/mach-exynos')
| -rw-r--r-- | arch/arm/mach-exynos/Kconfig | 126 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/Makefile | 31 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/Makefile.boot | 2 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/common.h | 174 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/exynos-smc.S | 22 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/exynos.c | 361 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/firmware.c | 97 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/headsmp.S | 41 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/hotplug.c | 92 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/include/mach/dma.h | 26 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/include/mach/map.h | 73 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/include/mach/memory.h | 27 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/mcpm-exynos.c | 358 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/mfc.h | 16 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/platsmp.c | 262 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/pm.c | 483 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/pm_domains.c | 243 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/pmu.c | 423 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/regs-pmu.h | 326 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/sleep.S | 57 | ||||
| -rw-r--r-- | arch/arm/mach-exynos/smc.h | 31 | 
21 files changed, 3271 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig new file mode 100644 index 00000000000..8f9b66c4ac7 --- /dev/null +++ b/arch/arm/mach-exynos/Kconfig @@ -0,0 +1,126 @@ +# arch/arm/mach-exynos/Kconfig +# +# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. +#		http://www.samsung.com/ +# +# Licensed under GPLv2 + +# Configuration options for the EXYNOS4 + +menuconfig ARCH_EXYNOS +	bool "Samsung EXYNOS" if ARCH_MULTI_V7 +	select ARCH_HAS_BANDGAP +	select ARCH_HAS_HOLES_MEMORYMODEL +	select ARCH_REQUIRE_GPIOLIB +	select ARM_AMBA +	select ARM_GIC +	select COMMON_CLK_SAMSUNG +	select HAVE_ARM_SCU if SMP +	select HAVE_S3C2410_I2C if I2C +	select HAVE_S3C2410_WATCHDOG if WATCHDOG +	select HAVE_S3C_RTC if RTC_CLASS +	select PINCTRL +	select PINCTRL_EXYNOS +	select PM_GENERIC_DOMAINS if PM_RUNTIME +	select S5P_DEV_MFC +	select SRAM +	help +	  Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5) + +if ARCH_EXYNOS + +config ARCH_EXYNOS3 +	bool "SAMSUNG EXYNOS3" +	select ARM_CPU_SUSPEND if PM +	help +	  Samsung EXYNOS3 (Crotex-A7) SoC based systems + +config ARCH_EXYNOS4 +	bool "SAMSUNG EXYNOS4" +	default y +	select ARM_CPU_SUSPEND if PM_SLEEP +	select CLKSRC_SAMSUNG_PWM if CPU_EXYNOS4210 +	select CPU_EXYNOS4210 +	select GIC_NON_BANKED +	select KEYBOARD_SAMSUNG if INPUT_KEYBOARD +	select MIGHT_HAVE_CACHE_L2X0 +	help +	  Samsung EXYNOS4 (Cortex-A9) SoC based systems + +config ARCH_EXYNOS5 +	bool "SAMSUNG EXYNOS5" +	default y +	help +	  Samsung EXYNOS5 (Cortex-A15/A7) SoC based systems + +comment "EXYNOS SoCs" + +config SOC_EXYNOS3250 +	bool "SAMSUNG EXYNOS3250" +	default y +	depends on ARCH_EXYNOS3 + +config CPU_EXYNOS4210 +	bool "SAMSUNG EXYNOS4210" +	default y +	depends on ARCH_EXYNOS4 + +config SOC_EXYNOS4212 +	bool "SAMSUNG EXYNOS4212" +	default y +	depends on ARCH_EXYNOS4 + +config SOC_EXYNOS4412 +	bool "SAMSUNG EXYNOS4412" +	default y +	depends on ARCH_EXYNOS4 + +config SOC_EXYNOS5250 +	bool "SAMSUNG EXYNOS5250" +	default y +	depends on ARCH_EXYNOS5 + +config SOC_EXYNOS5260 +	bool "SAMSUNG EXYNOS5260" +	default y +	depends on ARCH_EXYNOS5 + +config SOC_EXYNOS5410 +	bool "SAMSUNG EXYNOS5410" +	default y +	depends on ARCH_EXYNOS5 + +config SOC_EXYNOS5420 +	bool "SAMSUNG EXYNOS5420" +	default y +	depends on ARCH_EXYNOS5 + +config SOC_EXYNOS5440 +	bool "SAMSUNG EXYNOS5440" +	default y +	depends on ARCH_EXYNOS5 +	select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE +	select ARCH_HAS_OPP +	select HAVE_ARM_ARCH_TIMER +	select AUTO_ZRELADDR +	select MIGHT_HAVE_PCI +	select PCI_DOMAINS if PCI +	select PINCTRL_EXYNOS5440 +	select PM_OPP +	help +	  Enable EXYNOS5440 SoC support + +config SOC_EXYNOS5800 +	bool "SAMSUNG EXYNOS5800" +	default y +	depends on SOC_EXYNOS5420 + +config EXYNOS5420_MCPM +	bool "Exynos5420 Multi-Cluster PM support" +	depends on MCPM && SOC_EXYNOS5420 +	select ARM_CCI +	help +	  This is needed to provide CPU and cluster power management +	  on Exynos5420 implementing big.LITTLE. + +endif diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile new file mode 100644 index 00000000000..788f26d2114 --- /dev/null +++ b/arch/arm/mach-exynos/Makefile @@ -0,0 +1,31 @@ +# arch/arm/mach-exynos/Makefile +# +# Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. +#		http://www.samsung.com/ +# +# Licensed under GPLv2 + +ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree)/arch/arm/plat-samsung/include + +obj-y				:= +obj-m				:= +obj-n				:= +obj-				:= + +# Core + +obj-$(CONFIG_ARCH_EXYNOS)	+= exynos.o pmu.o exynos-smc.o firmware.o + +obj-$(CONFIG_PM_SLEEP)		+= pm.o sleep.o +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o + +obj-$(CONFIG_SMP)		+= platsmp.o headsmp.o + +obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o +CFLAGS_hotplug.o		+= -march=armv7-a + +plus_sec := $(call as-instr,.arch_extension sec,+sec) +AFLAGS_exynos-smc.o		:=-Wa,-march=armv7-a$(plus_sec) + +obj-$(CONFIG_EXYNOS5420_MCPM)	+= mcpm-exynos.o +CFLAGS_mcpm-exynos.o		+= -march=armv7-a diff --git a/arch/arm/mach-exynos/Makefile.boot b/arch/arm/mach-exynos/Makefile.boot new file mode 100644 index 00000000000..b9862e22bf1 --- /dev/null +++ b/arch/arm/mach-exynos/Makefile.boot @@ -0,0 +1,2 @@ +   zreladdr-y	+= 0x40008000 +params_phys-y	:= 0x40000100 diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h new file mode 100644 index 00000000000..1ee91763fa7 --- /dev/null +++ b/arch/arm/mach-exynos/common.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Common Header for EXYNOS machines + * + * 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. + */ + +#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H +#define __ARCH_ARM_MACH_EXYNOS_COMMON_H + +#include <linux/reboot.h> +#include <linux/of.h> + +#define EXYNOS3250_SOC_ID	0xE3472000 +#define EXYNOS3_SOC_MASK	0xFFFFF000 + +#define EXYNOS4210_CPU_ID	0x43210000 +#define EXYNOS4212_CPU_ID	0x43220000 +#define EXYNOS4412_CPU_ID	0xE4412200 +#define EXYNOS4_CPU_MASK	0xFFFE0000 + +#define EXYNOS5250_SOC_ID	0x43520000 +#define EXYNOS5410_SOC_ID	0xE5410000 +#define EXYNOS5420_SOC_ID	0xE5420000 +#define EXYNOS5440_SOC_ID	0xE5440000 +#define EXYNOS5800_SOC_ID	0xE5422000 +#define EXYNOS5_SOC_MASK	0xFFFFF000 + +extern unsigned long samsung_cpu_id; + +#define IS_SAMSUNG_CPU(name, id, mask)		\ +static inline int is_samsung_##name(void)	\ +{						\ +	return ((samsung_cpu_id & mask) == (id & mask));	\ +} + +IS_SAMSUNG_CPU(exynos3250, EXYNOS3250_SOC_ID, EXYNOS3_SOC_MASK) +IS_SAMSUNG_CPU(exynos4210, EXYNOS4210_CPU_ID, EXYNOS4_CPU_MASK) +IS_SAMSUNG_CPU(exynos4212, EXYNOS4212_CPU_ID, EXYNOS4_CPU_MASK) +IS_SAMSUNG_CPU(exynos4412, EXYNOS4412_CPU_ID, EXYNOS4_CPU_MASK) +IS_SAMSUNG_CPU(exynos5250, EXYNOS5250_SOC_ID, EXYNOS5_SOC_MASK) +IS_SAMSUNG_CPU(exynos5410, EXYNOS5410_SOC_ID, EXYNOS5_SOC_MASK) +IS_SAMSUNG_CPU(exynos5420, EXYNOS5420_SOC_ID, EXYNOS5_SOC_MASK) +IS_SAMSUNG_CPU(exynos5440, EXYNOS5440_SOC_ID, EXYNOS5_SOC_MASK) +IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK) + +#if defined(CONFIG_SOC_EXYNOS3250) +# define soc_is_exynos3250()	is_samsung_exynos3250() +#else +# define soc_is_exynos3250()	0 +#endif + +#if defined(CONFIG_CPU_EXYNOS4210) +# define soc_is_exynos4210()	is_samsung_exynos4210() +#else +# define soc_is_exynos4210()	0 +#endif + +#if defined(CONFIG_SOC_EXYNOS4212) +# define soc_is_exynos4212()	is_samsung_exynos4212() +#else +# define soc_is_exynos4212()	0 +#endif + +#if defined(CONFIG_SOC_EXYNOS4412) +# define soc_is_exynos4412()	is_samsung_exynos4412() +#else +# define soc_is_exynos4412()	0 +#endif + +#define EXYNOS4210_REV_0	(0x0) +#define EXYNOS4210_REV_1_0	(0x10) +#define EXYNOS4210_REV_1_1	(0x11) + +#if defined(CONFIG_SOC_EXYNOS5250) +# define soc_is_exynos5250()	is_samsung_exynos5250() +#else +# define soc_is_exynos5250()	0 +#endif + +#if defined(CONFIG_SOC_EXYNOS5410) +# define soc_is_exynos5410()	is_samsung_exynos5410() +#else +# define soc_is_exynos5410()	0 +#endif + +#if defined(CONFIG_SOC_EXYNOS5420) +# define soc_is_exynos5420()	is_samsung_exynos5420() +#else +# define soc_is_exynos5420()	0 +#endif + +#if defined(CONFIG_SOC_EXYNOS5440) +# define soc_is_exynos5440()	is_samsung_exynos5440() +#else +# define soc_is_exynos5440()	0 +#endif + +#if defined(CONFIG_SOC_EXYNOS5800) +# define soc_is_exynos5800()	is_samsung_exynos5800() +#else +# define soc_is_exynos5800()	0 +#endif + +#define soc_is_exynos4() (soc_is_exynos4210() || soc_is_exynos4212() || \ +			  soc_is_exynos4412()) +#define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \ +			  soc_is_exynos5420() || soc_is_exynos5800()) + +void mct_init(void __iomem *base, int irq_g0, int irq_l0, int irq_l1); + +struct map_desc; +extern void __iomem *sysram_ns_base_addr; +extern void __iomem *sysram_base_addr; +void exynos_init_io(void); +void exynos_restart(enum reboot_mode mode, const char *cmd); +void exynos_sysram_init(void); +void exynos_cpuidle_init(void); +void exynos_cpufreq_init(void); +void exynos_init_late(void); + +void exynos_firmware_init(void); + +#ifdef CONFIG_PINCTRL_EXYNOS +extern u32 exynos_get_eint_wake_mask(void); +#else +static inline u32 exynos_get_eint_wake_mask(void) { return 0xffffffff; } +#endif + +#ifdef CONFIG_PM_SLEEP +extern void __init exynos_pm_init(void); +#else +static inline void exynos_pm_init(void) {} +#endif + +extern void exynos_cpu_resume(void); + +extern struct smp_operations exynos_smp_ops; + +extern void exynos_cpu_die(unsigned int cpu); + +/* PMU(Power Management Unit) support */ + +#define PMU_TABLE_END	NULL + +enum sys_powerdown { +	SYS_AFTR, +	SYS_LPA, +	SYS_SLEEP, +	NUM_SYS_POWERDOWN, +}; + +struct exynos_pmu_conf { +	void __iomem *reg; +	unsigned int val[NUM_SYS_POWERDOWN]; +}; + +extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); +extern void exynos_cpu_power_down(int cpu); +extern void exynos_cpu_power_up(int cpu); +extern int  exynos_cpu_power_state(int cpu); +extern void exynos_cluster_power_down(int cluster); +extern void exynos_cluster_power_up(int cluster); +extern int  exynos_cluster_power_state(int cluster); +extern void exynos_enter_aftr(void); + +extern void s5p_init_cpu(void __iomem *cpuid_addr); +extern unsigned int samsung_rev(void); + +#endif /* __ARCH_ARM_MACH_EXYNOS_COMMON_H */ diff --git a/arch/arm/mach-exynos/exynos-smc.S b/arch/arm/mach-exynos/exynos-smc.S new file mode 100644 index 00000000000..2e27aa3813f --- /dev/null +++ b/arch/arm/mach-exynos/exynos-smc.S @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2012 Samsung Electronics. + * + * Copied from omap-smc.S Copyright (C) 2010 Texas Instruments, Inc. + * + * 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/linkage.h> + +/* + * Function signature: void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3) + */ + +ENTRY(exynos_smc) +	stmfd	sp!, {r4-r11, lr} +	dsb +	smc	#0 +	ldmfd	sp!, {r4-r11, pc} +ENDPROC(exynos_smc) diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c new file mode 100644 index 00000000000..66c9b9614f3 --- /dev/null +++ b/arch/arm/mach-exynos/exynos.c @@ -0,0 +1,361 @@ +/* + * SAMSUNG EXYNOS Flattened Device Tree enabled machine + * + * Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * 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/io.h> +#include <linux/kernel.h> +#include <linux/serial_s3c.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_fdt.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> + +#include <asm/cacheflush.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/memory.h> + +#include "common.h" +#include "mfc.h" +#include "regs-pmu.h" + +static struct map_desc exynos4_iodesc[] __initdata = { +	{ +		.virtual	= (unsigned long)S3C_VA_SYS, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_SYSCON), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S3C_VA_TIMER, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_TIMER), +		.length		= SZ_16K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S3C_VA_WATCHDOG, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_WATCHDOG), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_SROMC, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_SROMC), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_SYSTIMER, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_SYSTIMER), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_PMU, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_PMU), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_COMBINER_BASE, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_COMBINER), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_GIC_CPU, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_GIC_CPU), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_GIC_DIST, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_GIC_DIST), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_CMU, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_CMU), +		.length		= SZ_128K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_COREPERI_BASE, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_COREPERI), +		.length		= SZ_8K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_L2CC, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_L2CC), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_DMC0, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_DMC0), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_DMC1, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_DMC1), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S3C_VA_USB_HSPHY, +		.pfn		= __phys_to_pfn(EXYNOS4_PA_HSPHY), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, +}; + +static struct map_desc exynos5_iodesc[] __initdata = { +	{ +		.virtual	= (unsigned long)S3C_VA_SYS, +		.pfn		= __phys_to_pfn(EXYNOS5_PA_SYSCON), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S3C_VA_TIMER, +		.pfn		= __phys_to_pfn(EXYNOS5_PA_TIMER), +		.length		= SZ_16K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S3C_VA_WATCHDOG, +		.pfn		= __phys_to_pfn(EXYNOS5_PA_WATCHDOG), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_SROMC, +		.pfn		= __phys_to_pfn(EXYNOS5_PA_SROMC), +		.length		= SZ_4K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_CMU, +		.pfn		= __phys_to_pfn(EXYNOS5_PA_CMU), +		.length		= 144 * SZ_1K, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (unsigned long)S5P_VA_PMU, +		.pfn		= __phys_to_pfn(EXYNOS5_PA_PMU), +		.length		= SZ_64K, +		.type		= MT_DEVICE, +	}, +}; + +void exynos_restart(enum reboot_mode mode, const char *cmd) +{ +	struct device_node *np; +	u32 val = 0x1; +	void __iomem *addr = EXYNOS_SWRESET; + +	if (of_machine_is_compatible("samsung,exynos5440")) { +		u32 status; +		np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock"); + +		addr = of_iomap(np, 0) + 0xbc; +		status = __raw_readl(addr); + +		addr = of_iomap(np, 0) + 0xcc; +		val = __raw_readl(addr); + +		val = (val & 0xffff0000) | (status & 0xffff); +	} + +	__raw_writel(val, addr); +} + +static struct platform_device exynos_cpuidle = { +	.name              = "exynos_cpuidle", +	.dev.platform_data = exynos_enter_aftr, +	.id                = -1, +}; + +void __init exynos_cpuidle_init(void) +{ +	if (soc_is_exynos4210() || soc_is_exynos5250()) +		platform_device_register(&exynos_cpuidle); +} + +void __init exynos_cpufreq_init(void) +{ +	platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); +} + +void __iomem *sysram_base_addr; +void __iomem *sysram_ns_base_addr; + +void __init exynos_sysram_init(void) +{ +	struct device_node *node; + +	for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram") { +		if (!of_device_is_available(node)) +			continue; +		sysram_base_addr = of_iomap(node, 0); +		break; +	} + +	for_each_compatible_node(node, NULL, "samsung,exynos4210-sysram-ns") { +		if (!of_device_is_available(node)) +			continue; +		sysram_ns_base_addr = of_iomap(node, 0); +		break; +	} +} + +void __init exynos_init_late(void) +{ +	if (of_machine_is_compatible("samsung,exynos5440")) +		/* to be supported later */ +		return; + +	pm_genpd_poweroff_unused(); +	exynos_pm_init(); +} + +static int __init exynos_fdt_map_chipid(unsigned long node, const char *uname, +					int depth, void *data) +{ +	struct map_desc iodesc; +	const __be32 *reg; +	int len; + +	if (!of_flat_dt_is_compatible(node, "samsung,exynos4210-chipid") && +		!of_flat_dt_is_compatible(node, "samsung,exynos5440-clock")) +		return 0; + +	reg = of_get_flat_dt_prop(node, "reg", &len); +	if (reg == NULL || len != (sizeof(unsigned long) * 2)) +		return 0; + +	iodesc.pfn = __phys_to_pfn(be32_to_cpu(reg[0])); +	iodesc.length = be32_to_cpu(reg[1]) - 1; +	iodesc.virtual = (unsigned long)S5P_VA_CHIPID; +	iodesc.type = MT_DEVICE; +	iotable_init(&iodesc, 1); +	return 1; +} + +/* + * exynos_map_io + * + * register the standard cpu IO areas + */ +static void __init exynos_map_io(void) +{ +	if (soc_is_exynos4()) +		iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc)); + +	if (soc_is_exynos5()) +		iotable_init(exynos5_iodesc, ARRAY_SIZE(exynos5_iodesc)); +} + +void __init exynos_init_io(void) +{ +	debug_ll_io_init(); + +	of_scan_flat_dt(exynos_fdt_map_chipid, NULL); + +	/* detect cpu id and rev. */ +	s5p_init_cpu(S5P_VA_CHIPID); + +	exynos_map_io(); +} + +static void __init exynos_dt_machine_init(void) +{ +	struct device_node *i2c_np; +	const char *i2c_compat = "samsung,s3c2440-i2c"; +	unsigned int tmp; +	int id; + +	/* +	 * Exynos5's legacy i2c controller and new high speed i2c +	 * controller have muxed interrupt sources. By default the +	 * interrupts for 4-channel HS-I2C controller are enabled. +	 * If node for first four channels of legacy i2c controller +	 * are available then re-configure the interrupts via the +	 * system register. +	 */ +	if (soc_is_exynos5()) { +		for_each_compatible_node(i2c_np, NULL, i2c_compat) { +			if (of_device_is_available(i2c_np)) { +				id = of_alias_get_id(i2c_np, "i2c"); +				if (id < 4) { +					tmp = readl(EXYNOS5_SYS_I2C_CFG); +					writel(tmp & ~(0x1 << id), +							EXYNOS5_SYS_I2C_CFG); +				} +			} +		} +	} + +	/* +	 * This is called from smp_prepare_cpus if we've built for SMP, but +	 * we still need to set it up for PM and firmware ops if not. +	 */ +	if (!IS_ENABLED(CONFIG_SMP)) +		exynos_sysram_init(); + +	exynos_cpuidle_init(); +	exynos_cpufreq_init(); + +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +} + +static char const *exynos_dt_compat[] __initconst = { +	"samsung,exynos3", +	"samsung,exynos3250", +	"samsung,exynos4", +	"samsung,exynos4210", +	"samsung,exynos4212", +	"samsung,exynos4412", +	"samsung,exynos5", +	"samsung,exynos5250", +	"samsung,exynos5260", +	"samsung,exynos5420", +	"samsung,exynos5440", +	NULL +}; + +static void __init exynos_reserve(void) +{ +#ifdef CONFIG_S5P_DEV_MFC +	int i; +	char *mfc_mem[] = { +		"samsung,mfc-v5", +		"samsung,mfc-v6", +		"samsung,mfc-v7", +	}; + +	for (i = 0; i < ARRAY_SIZE(mfc_mem); i++) +		if (of_scan_flat_dt(s5p_fdt_alloc_mfc_mem, mfc_mem[i])) +			break; +#endif +} + +static void __init exynos_dt_fixup(void) +{ +	/* +	 * Some versions of uboot pass garbage entries in the memory node, +	 * use the old CONFIG_ARM_NR_BANKS +	 */ +	of_fdt_limit_memory(8); +} + +DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") +	/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */ +	/* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */ +	.l2c_aux_val	= 0x3c400001, +	.l2c_aux_mask	= 0xc20fffff, +	.smp		= smp_ops(exynos_smp_ops), +	.map_io		= exynos_init_io, +	.init_early	= exynos_firmware_init, +	.init_machine	= exynos_dt_machine_init, +	.init_late	= exynos_init_late, +	.dt_compat	= exynos_dt_compat, +	.restart	= exynos_restart, +	.reserve	= exynos_reserve, +	.dt_fixup	= exynos_dt_fixup, +MACHINE_END diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c new file mode 100644 index 00000000000..e8797bb7887 --- /dev/null +++ b/arch/arm/mach-exynos/firmware.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2012 Samsung Electronics. + * Kyungmin Park <kyungmin.park@samsung.com> + * Tomasz Figa <t.figa@samsung.com> + * + * 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/kernel.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/of_address.h> + +#include <asm/firmware.h> + +#include <mach/map.h> + +#include "common.h" +#include "smc.h" + +static int exynos_do_idle(void) +{ +	exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); +	return 0; +} + +static int exynos_cpu_boot(int cpu) +{ +	/* +	 * Exynos3250 doesn't need to send smc command for secondary CPU boot +	 * because Exynos3250 removes WFE in secure mode. +	 */ +	if (soc_is_exynos3250()) +		return 0; + +	/* +	 * The second parameter of SMC_CMD_CPU1BOOT command means CPU id. +	 * But, Exynos4212 has only one secondary CPU so second parameter +	 * isn't used for informing secure firmware about CPU id. +	 */ +	if (soc_is_exynos4212()) +		cpu = 0; + +	exynos_smc(SMC_CMD_CPU1BOOT, cpu, 0, 0); +	return 0; +} + +static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) +{ +	void __iomem *boot_reg; + +	if (!sysram_ns_base_addr) +		return -ENODEV; + +	boot_reg = sysram_ns_base_addr + 0x1c; + +	/* +	 * Almost all Exynos-series of SoCs that run in secure mode don't need +	 * additional offset for every CPU, with Exynos4412 being the only +	 * exception. +	 */ +	if (soc_is_exynos4412()) +		boot_reg += 4 * cpu; + +	__raw_writel(boot_addr, boot_reg); +	return 0; +} + +static const struct firmware_ops exynos_firmware_ops = { +	.do_idle		= exynos_do_idle, +	.set_cpu_boot_addr	= exynos_set_cpu_boot_addr, +	.cpu_boot		= exynos_cpu_boot, +}; + +void __init exynos_firmware_init(void) +{ +	struct device_node *nd; +	const __be32 *addr; + +	nd = of_find_compatible_node(NULL, NULL, +					"samsung,secure-firmware"); +	if (!nd) +		return; + +	addr = of_get_address(nd, 0, NULL, NULL); +	if (!addr) { +		pr_err("%s: No address specified.\n", __func__); +		return; +	} + +	pr_info("Running under secure firmware.\n"); + +	register_firmware_ops(&exynos_firmware_ops); +} diff --git a/arch/arm/mach-exynos/headsmp.S b/arch/arm/mach-exynos/headsmp.S new file mode 100644 index 00000000000..cdd9d91e993 --- /dev/null +++ b/arch/arm/mach-exynos/headsmp.S @@ -0,0 +1,41 @@ +/* + *  linux/arch/arm/mach-exynos4/headsmp.S + * + *  Cloned from linux/arch/arm/mach-realview/headsmp.S + * + *  Copyright (c) 2003 ARM Limited + *  All Rights Reserved + * + * 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/linkage.h> +#include <linux/init.h> + +/* + * exynos4 specific entry point for secondary CPUs.  This provides + * a "holding pen" into which all secondary cores are held until we're + * ready for them to initialise. + */ +ENTRY(exynos4_secondary_startup) +	mrc	p15, 0, r0, c0, c0, 5 +	and	r0, r0, #15 +	adr	r4, 1f +	ldmia	r4, {r5, r6} +	sub	r4, r4, r5 +	add	r6, r6, r4 +pen:	ldr	r7, [r6] +	cmp	r7, r0 +	bne	pen + +	/* +	 * we've been released from the holding pen: secondary_stack +	 * should now contain the SVC stack for this core +	 */ +	b	secondary_startup +ENDPROC(exynos4_secondary_startup) + +	.align 2 +1:	.long	. +	.long	pen_release diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c new file mode 100644 index 00000000000..920a4baa53c --- /dev/null +++ b/arch/arm/mach-exynos/hotplug.c @@ -0,0 +1,92 @@ +/* linux arch/arm/mach-exynos4/hotplug.c + * + *  Cloned from linux/arch/arm/mach-realview/hotplug.c + * + *  Copyright (C) 2002 ARM Ltd. + *  All Rights Reserved + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/cp15.h> +#include <asm/smp_plat.h> + +#include "common.h" +#include "regs-pmu.h" + +static inline void cpu_leave_lowpower(void) +{ +	unsigned int v; + +	asm volatile( +	"mrc	p15, 0, %0, c1, c0, 0\n" +	"	orr	%0, %0, %1\n" +	"	mcr	p15, 0, %0, c1, c0, 0\n" +	"	mrc	p15, 0, %0, c1, c0, 1\n" +	"	orr	%0, %0, %2\n" +	"	mcr	p15, 0, %0, c1, c0, 1\n" +	  : "=&r" (v) +	  : "Ir" (CR_C), "Ir" (0x40) +	  : "cc"); +} + +static inline void platform_do_lowpower(unsigned int cpu, int *spurious) +{ +	u32 mpidr = cpu_logical_map(cpu); +	u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); + +	for (;;) { + +		/* Turn the CPU off on next WFI instruction. */ +		exynos_cpu_power_down(core_id); + +		wfi(); + +		if (pen_release == core_id) { +			/* +			 * OK, proper wakeup, we're done +			 */ +			break; +		} + +		/* +		 * Getting here, means that we have come out of WFI without +		 * having been woken up - this shouldn't happen +		 * +		 * Just note it happening - when we're woken, we can report +		 * its occurrence. +		 */ +		(*spurious)++; +	} +} + +/* + * platform-specific code to shutdown a CPU + * + * Called with IRQs disabled + */ +void __ref exynos_cpu_die(unsigned int cpu) +{ +	int spurious = 0; + +	v7_exit_coherency_flush(louis); + +	platform_do_lowpower(cpu, &spurious); + +	/* +	 * bring this CPU back into the world of cache +	 * coherency, and then restore interrupts +	 */ +	cpu_leave_lowpower(); + +	if (spurious) +		pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); +} diff --git a/arch/arm/mach-exynos/include/mach/dma.h b/arch/arm/mach-exynos/include/mach/dma.h new file mode 100644 index 00000000000..201842a3769 --- /dev/null +++ b/arch/arm/mach-exynos/include/mach/dma.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2010 Samsung Electronics Co. Ltd. + *	Jaswinder Singh <jassi.brar@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MACH_DMA_H +#define __MACH_DMA_H + +/* This platform uses the common DMA API driver for PL330 */ +#include <plat/dma-pl330.h> + +#endif /* __MACH_DMA_H */ diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h new file mode 100644 index 00000000000..548269a6063 --- /dev/null +++ b/arch/arm/mach-exynos/include/mach/map.h @@ -0,0 +1,73 @@ +/* linux/arch/arm/mach-exynos/include/mach/map.h + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + *		http://www.samsung.com/ + * + * EXYNOS4 - Memory map definitions + * + * 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. +*/ + +#ifndef __ASM_ARCH_MAP_H +#define __ASM_ARCH_MAP_H __FILE__ + +#include <plat/map-base.h> + +/* + * EXYNOS4 UART offset is 0x10000 but the older S5P SoCs are 0x400. + * So need to define it, and here is to avoid redefinition warning. + */ +#define S3C_UART_OFFSET			(0x10000) + +#include <plat/map-s5p.h> + +#define EXYNOS_PA_CHIPID		0x10000000 + +#define EXYNOS4_PA_SYSCON		0x10010000 +#define EXYNOS5_PA_SYSCON		0x10050100 + +#define EXYNOS4_PA_PMU			0x10020000 +#define EXYNOS5_PA_PMU			0x10040000 + +#define EXYNOS4_PA_CMU			0x10030000 +#define EXYNOS5_PA_CMU			0x10010000 + +#define EXYNOS4_PA_SYSTIMER		0x10050000 + +#define EXYNOS4_PA_WATCHDOG		0x10060000 +#define EXYNOS5_PA_WATCHDOG		0x101D0000 + +#define EXYNOS4_PA_DMC0			0x10400000 +#define EXYNOS4_PA_DMC1			0x10410000 + +#define EXYNOS4_PA_COMBINER		0x10440000 +#define EXYNOS5_PA_COMBINER		0x10440000 + +#define EXYNOS4_PA_GIC_CPU		0x10480000 +#define EXYNOS4_PA_GIC_DIST		0x10490000 +#define EXYNOS5_PA_GIC_CPU		0x10482000 +#define EXYNOS5_PA_GIC_DIST		0x10481000 + +#define EXYNOS4_PA_COREPERI		0x10500000 +#define EXYNOS4_PA_L2CC			0x10502000 + +#define EXYNOS4_PA_SROMC		0x12570000 +#define EXYNOS5_PA_SROMC		0x12250000 + +#define EXYNOS4_PA_HSPHY		0x125B0000 + +#define EXYNOS4_PA_UART			0x13800000 +#define EXYNOS5_PA_UART			0x12C00000 + +#define EXYNOS4_PA_TIMER		0x139D0000 +#define EXYNOS5_PA_TIMER		0x12DD0000 + +/* Compatibility UART */ + +#define EXYNOS5440_PA_UART0		0x000B0000 + +#define S3C_VA_UARTx(x)			(S3C_VA_UART + ((x) * S3C_UART_OFFSET)) + +#endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/mach-exynos/include/mach/memory.h b/arch/arm/mach-exynos/include/mach/memory.h new file mode 100644 index 00000000000..2a4cdb7cb32 --- /dev/null +++ b/arch/arm/mach-exynos/include/mach/memory.h @@ -0,0 +1,27 @@ +/* linux/arch/arm/mach-exynos4/include/mach/memory.h + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * EXYNOS4 - Memory definitions + * + * 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. +*/ + +#ifndef __ASM_ARCH_MEMORY_H +#define __ASM_ARCH_MEMORY_H __FILE__ + +#define PLAT_PHYS_OFFSET		UL(0x40000000) + +#ifndef CONFIG_ARM_LPAE +/* Maximum of 256MiB in one bank */ +#define MAX_PHYSMEM_BITS	32 +#define SECTION_SIZE_BITS	28 +#else +#define MAX_PHYSMEM_BITS	36 +#define SECTION_SIZE_BITS	31 +#endif + +#endif /* __ASM_ARCH_MEMORY_H */ diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c new file mode 100644 index 00000000000..ace0ed61747 --- /dev/null +++ b/arch/arm/mach-exynos/mcpm-exynos.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * arch/arm/mach-exynos/mcpm-exynos.c + * + * Based on arch/arm/mach-vexpress/dcscb.c + * + * 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/arm-cci.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of_address.h> + +#include <asm/cputype.h> +#include <asm/cp15.h> +#include <asm/mcpm.h> + +#include "regs-pmu.h" +#include "common.h" + +#define EXYNOS5420_CPUS_PER_CLUSTER	4 +#define EXYNOS5420_NR_CLUSTERS		2 + +/* + * The common v7_exit_coherency_flush API could not be used because of the + * Erratum 799270 workaround. This macro is the same as the common one (in + * arch/arm/include/asm/cacheflush.h) except for the erratum handling. + */ +#define exynos_v7_exit_coherency_flush(level) \ +	asm volatile( \ +	"stmfd	sp!, {fp, ip}\n\t"\ +	"mrc	p15, 0, r0, c1, c0, 0	@ get SCTLR\n\t" \ +	"bic	r0, r0, #"__stringify(CR_C)"\n\t" \ +	"mcr	p15, 0, r0, c1, c0, 0	@ set SCTLR\n\t" \ +	"isb\n\t"\ +	"bl	v7_flush_dcache_"__stringify(level)"\n\t" \ +	"clrex\n\t"\ +	"mrc	p15, 0, r0, c1, c0, 1	@ get ACTLR\n\t" \ +	"bic	r0, r0, #(1 << 6)	@ disable local coherency\n\t" \ +	/* Dummy Load of a device register to avoid Erratum 799270 */ \ +	"ldr	r4, [%0]\n\t" \ +	"and	r4, r4, #0\n\t" \ +	"orr	r0, r0, r4\n\t" \ +	"mcr	p15, 0, r0, c1, c0, 1	@ set ACTLR\n\t" \ +	"isb\n\t" \ +	"dsb\n\t" \ +	"ldmfd	sp!, {fp, ip}" \ +	: \ +	: "Ir" (S5P_INFORM0) \ +	: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ +	  "r9", "r10", "lr", "memory") + +/* + * We can't use regular spinlocks. In the switcher case, it is possible + * for an outbound CPU to call power_down() after its inbound counterpart + * is already live using the same logical CPU number which trips lockdep + * debugging. + */ +static arch_spinlock_t exynos_mcpm_lock = __ARCH_SPIN_LOCK_UNLOCKED; +static int +cpu_use_count[EXYNOS5420_CPUS_PER_CLUSTER][EXYNOS5420_NR_CLUSTERS]; + +#define exynos_cluster_usecnt(cluster) \ +	(cpu_use_count[0][cluster] +   \ +	 cpu_use_count[1][cluster] +   \ +	 cpu_use_count[2][cluster] +   \ +	 cpu_use_count[3][cluster]) + +#define exynos_cluster_unused(cluster) !exynos_cluster_usecnt(cluster) + +static int exynos_cluster_power_control(unsigned int cluster, int enable) +{ +	unsigned int tries = 100; +	unsigned int val; + +	if (enable) { +		exynos_cluster_power_up(cluster); +		val = S5P_CORE_LOCAL_PWR_EN; +	} else { +		exynos_cluster_power_down(cluster); +		val = 0; +	} + +	/* Wait until cluster power control is applied */ +	while (tries--) { +		if (exynos_cluster_power_state(cluster) == val) +			return 0; + +		cpu_relax(); +	} +	pr_debug("timed out waiting for cluster %u to power %s\n", cluster, +		enable ? "on" : "off"); + +	return -ETIMEDOUT; +} + +static int exynos_power_up(unsigned int cpu, unsigned int cluster) +{ +	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER); +	int err = 0; + +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); +	if (cpu >= EXYNOS5420_CPUS_PER_CLUSTER || +		cluster >= EXYNOS5420_NR_CLUSTERS) +		return -EINVAL; + +	/* +	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq +	 * variant exists, we need to disable IRQs manually here. +	 */ +	local_irq_disable(); +	arch_spin_lock(&exynos_mcpm_lock); + +	cpu_use_count[cpu][cluster]++; +	if (cpu_use_count[cpu][cluster] == 1) { +		bool was_cluster_down = +			(exynos_cluster_usecnt(cluster) == 1); + +		/* +		 * Turn on the cluster (L2/COMMON) and then power on the +		 * cores. +		 */ +		if (was_cluster_down) +			err = exynos_cluster_power_control(cluster, 1); + +		if (!err) +			exynos_cpu_power_up(cpunr); +		else +			exynos_cluster_power_control(cluster, 0); +	} else if (cpu_use_count[cpu][cluster] != 2) { +		/* +		 * The only possible values are: +		 * 0 = CPU down +		 * 1 = CPU (still) up +		 * 2 = CPU requested to be up before it had a chance +		 *     to actually make itself down. +		 * Any other value is a bug. +		 */ +		BUG(); +	} + +	arch_spin_unlock(&exynos_mcpm_lock); +	local_irq_enable(); + +	return err; +} + +/* + * NOTE: This function requires the stack data to be visible through power down + * and can only be executed on processors like A15 and A7 that hit the cache + * with the C bit clear in the SCTLR register. + */ +static void exynos_power_down(void) +{ +	unsigned int mpidr, cpu, cluster; +	bool last_man = false, skip_wfi = false; +	unsigned int cpunr; + +	mpidr = read_cpuid_mpidr(); +	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); +	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); +	cpunr =  cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER); + +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); +	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER || +			cluster >= EXYNOS5420_NR_CLUSTERS); + +	__mcpm_cpu_going_down(cpu, cluster); + +	arch_spin_lock(&exynos_mcpm_lock); +	BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP); +	cpu_use_count[cpu][cluster]--; +	if (cpu_use_count[cpu][cluster] == 0) { +		exynos_cpu_power_down(cpunr); + +		if (exynos_cluster_unused(cluster)) +			/* TODO: Turn off the cluster here to save power. */ +			last_man = true; +	} else if (cpu_use_count[cpu][cluster] == 1) { +		/* +		 * A power_up request went ahead of us. +		 * Even if we do not want to shut this CPU down, +		 * the caller expects a certain state as if the WFI +		 * was aborted.  So let's continue with cache cleaning. +		 */ +		skip_wfi = true; +	} else { +		BUG(); +	} + +	if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) { +		arch_spin_unlock(&exynos_mcpm_lock); + +		if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A15) { +			/* +			 * On the Cortex-A15 we need to disable +			 * L2 prefetching before flushing the cache. +			 */ +			asm volatile( +			"mcr	p15, 1, %0, c15, c0, 3\n\t" +			"isb\n\t" +			"dsb" +			: : "r" (0x400)); +		} + +		/* Flush all cache levels for this cluster. */ +		exynos_v7_exit_coherency_flush(all); + +		/* +		 * Disable cluster-level coherency by masking +		 * incoming snoops and DVM messages: +		 */ +		cci_disable_port_by_cpu(mpidr); + +		__mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN); +	} else { +		arch_spin_unlock(&exynos_mcpm_lock); + +		/* Disable and flush the local CPU cache. */ +		exynos_v7_exit_coherency_flush(louis); +	} + +	__mcpm_cpu_down(cpu, cluster); + +	/* Now we are prepared for power-down, do it: */ +	if (!skip_wfi) +		wfi(); + +	/* Not dead at this point?  Let our caller cope. */ +} + +static int exynos_wait_for_powerdown(unsigned int cpu, unsigned int cluster) +{ +	unsigned int tries = 100; +	unsigned int cpunr = cpu + (cluster * EXYNOS5420_CPUS_PER_CLUSTER); + +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); +	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER || +			cluster >= EXYNOS5420_NR_CLUSTERS); + +	/* Wait for the core state to be OFF */ +	while (tries--) { +		if (ACCESS_ONCE(cpu_use_count[cpu][cluster]) == 0) { +			if ((exynos_cpu_power_state(cpunr) == 0)) +				return 0; /* success: the CPU is halted */ +		} + +		/* Otherwise, wait and retry: */ +		msleep(1); +	} + +	return -ETIMEDOUT; /* timeout */ +} + +static const struct mcpm_platform_ops exynos_power_ops = { +	.power_up		= exynos_power_up, +	.power_down		= exynos_power_down, +	.wait_for_powerdown	= exynos_wait_for_powerdown, +}; + +static void __init exynos_mcpm_usage_count_init(void) +{ +	unsigned int mpidr, cpu, cluster; + +	mpidr = read_cpuid_mpidr(); +	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); +	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); + +	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster); +	BUG_ON(cpu >= EXYNOS5420_CPUS_PER_CLUSTER  || +			cluster >= EXYNOS5420_NR_CLUSTERS); + +	cpu_use_count[cpu][cluster] = 1; +} + +/* + * Enable cluster-level coherency, in preparation for turning on the MMU. + */ +static void __naked exynos_pm_power_up_setup(unsigned int affinity_level) +{ +	asm volatile ("\n" +	"cmp	r0, #1\n" +	"bxne	lr\n" +	"b	cci_enable_port_for_self"); +} + +static const struct of_device_id exynos_dt_mcpm_match[] = { +	{ .compatible = "samsung,exynos5420" }, +	{ .compatible = "samsung,exynos5800" }, +	{}, +}; + +static int __init exynos_mcpm_init(void) +{ +	struct device_node *node; +	void __iomem *ns_sram_base_addr; +	int ret; + +	node = of_find_matching_node(NULL, exynos_dt_mcpm_match); +	if (!node) +		return -ENODEV; +	of_node_put(node); + +	if (!cci_probed()) +		return -ENODEV; + +	node = of_find_compatible_node(NULL, NULL, +			"samsung,exynos4210-sysram-ns"); +	if (!node) +		return -ENODEV; + +	ns_sram_base_addr = of_iomap(node, 0); +	of_node_put(node); +	if (!ns_sram_base_addr) { +		pr_err("failed to map non-secure iRAM base address\n"); +		return -ENOMEM; +	} + +	/* +	 * To increase the stability of KFC reset we need to program +	 * the PMU SPARE3 register +	 */ +	__raw_writel(EXYNOS5420_SWRESET_KFC_SEL, S5P_PMU_SPARE3); + +	exynos_mcpm_usage_count_init(); + +	ret = mcpm_platform_register(&exynos_power_ops); +	if (!ret) +		ret = mcpm_sync_init(exynos_pm_power_up_setup); +	if (ret) { +		iounmap(ns_sram_base_addr); +		return ret; +	} + +	mcpm_smp_set_ops(); + +	pr_info("Exynos MCPM support installed\n"); + +	/* +	 * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr +	 * as part of secondary_cpu_start().  Let's redirect it to the +	 * mcpm_entry_point(). +	 */ +	__raw_writel(0xe59f0000, ns_sram_base_addr);     /* ldr r0, [pc, #0] */ +	__raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx  r0 */ +	__raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8); + +	iounmap(ns_sram_base_addr); + +	return ret; +} + +early_initcall(exynos_mcpm_init); diff --git a/arch/arm/mach-exynos/mfc.h b/arch/arm/mach-exynos/mfc.h new file mode 100644 index 00000000000..dec93cd5b3c --- /dev/null +++ b/arch/arm/mach-exynos/mfc.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2013 Samsung Electronics Co.Ltd + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + */ + +#ifndef __MACH_EXYNOS_MFC_H +#define __MACH_EXYNOS_MFC_H __FILE__ + +int __init s5p_fdt_alloc_mfc_mem(unsigned long node, const char *uname, +				int depth, void *data); + +#endif /* __MACH_EXYNOS_MFC_H */ diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c new file mode 100644 index 00000000000..50b9aad5e27 --- /dev/null +++ b/arch/arm/mach-exynos/platsmp.c @@ -0,0 +1,262 @@ +/* linux/arch/arm/mach-exynos4/platsmp.c + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Cloned from linux/arch/arm/mach-vexpress/platsmp.c + * + *  Copyright (C) 2002 ARM Ltd. + *  All Rights Reserved + * + * 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/errno.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/smp.h> +#include <linux/io.h> +#include <linux/of_address.h> + +#include <asm/cacheflush.h> +#include <asm/smp_plat.h> +#include <asm/smp_scu.h> +#include <asm/firmware.h> + +#include "common.h" +#include "regs-pmu.h" + +extern void exynos4_secondary_startup(void); + +static inline void __iomem *cpu_boot_reg_base(void) +{ +	if (soc_is_exynos4210() && samsung_rev() == EXYNOS4210_REV_1_1) +		return S5P_INFORM5; +	return sysram_base_addr; +} + +static inline void __iomem *cpu_boot_reg(int cpu) +{ +	void __iomem *boot_reg; + +	boot_reg = cpu_boot_reg_base(); +	if (!boot_reg) +		return ERR_PTR(-ENODEV); +	if (soc_is_exynos4412()) +		boot_reg += 4*cpu; +	else if (soc_is_exynos5420() || soc_is_exynos5800()) +		boot_reg += 4; +	return boot_reg; +} + +/* + * Write pen_release in a way that is guaranteed to be visible to all + * observers, irrespective of whether they're taking part in coherency + * or not.  This is necessary for the hotplug code to work reliably. + */ +static void write_pen_release(int val) +{ +	pen_release = val; +	smp_wmb(); +	sync_cache_w(&pen_release); +} + +static void __iomem *scu_base_addr(void) +{ +	return (void __iomem *)(S5P_VA_SCU); +} + +static DEFINE_SPINLOCK(boot_lock); + +static void exynos_secondary_init(unsigned int cpu) +{ +	/* +	 * let the primary processor know we're out of the +	 * pen, then head off into the C entry point +	 */ +	write_pen_release(-1); + +	/* +	 * Synchronise with the boot thread. +	 */ +	spin_lock(&boot_lock); +	spin_unlock(&boot_lock); +} + +static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) +{ +	unsigned long timeout; +	u32 mpidr = cpu_logical_map(cpu); +	u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); +	int ret = -ENOSYS; + +	/* +	 * Set synchronisation state between this boot processor +	 * and the secondary one +	 */ +	spin_lock(&boot_lock); + +	/* +	 * The secondary processor is waiting to be released from +	 * the holding pen - release it, then wait for it to flag +	 * that it has been released by resetting pen_release. +	 * +	 * Note that "pen_release" is the hardware CPU core ID, whereas +	 * "cpu" is Linux's internal ID. +	 */ +	write_pen_release(core_id); + +	if (!exynos_cpu_power_state(core_id)) { +		exynos_cpu_power_up(core_id); +		timeout = 10; + +		/* wait max 10 ms until cpu1 is on */ +		while (exynos_cpu_power_state(core_id) +		       != S5P_CORE_LOCAL_PWR_EN) { +			if (timeout-- == 0) +				break; + +			mdelay(1); +		} + +		if (timeout == 0) { +			printk(KERN_ERR "cpu1 power enable failed"); +			spin_unlock(&boot_lock); +			return -ETIMEDOUT; +		} +	} +	/* +	 * Send the secondary CPU a soft interrupt, thereby causing +	 * the boot monitor to read the system wide flags register, +	 * and branch to the address found there. +	 */ + +	timeout = jiffies + (1 * HZ); +	while (time_before(jiffies, timeout)) { +		unsigned long boot_addr; + +		smp_rmb(); + +		boot_addr = virt_to_phys(exynos4_secondary_startup); + +		/* +		 * Try to set boot address using firmware first +		 * and fall back to boot register if it fails. +		 */ +		ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); +		if (ret && ret != -ENOSYS) +			goto fail; +		if (ret == -ENOSYS) { +			void __iomem *boot_reg = cpu_boot_reg(core_id); + +			if (IS_ERR(boot_reg)) { +				ret = PTR_ERR(boot_reg); +				goto fail; +			} +			__raw_writel(boot_addr, cpu_boot_reg(core_id)); +		} + +		call_firmware_op(cpu_boot, core_id); + +		arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + +		if (pen_release == -1) +			break; + +		udelay(10); +	} + +	/* +	 * now the secondary core is starting up let it run its +	 * calibrations, then wait for it to finish +	 */ +fail: +	spin_unlock(&boot_lock); + +	return pen_release != -1 ? ret : 0; +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ + +static void __init exynos_smp_init_cpus(void) +{ +	void __iomem *scu_base = scu_base_addr(); +	unsigned int i, ncores; + +	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) +		ncores = scu_base ? scu_get_core_count(scu_base) : 1; +	else +		/* +		 * CPU Nodes are passed thru DT and set_cpu_possible +		 * is set by "arm_dt_init_cpu_maps". +		 */ +		return; + +	/* sanity check */ +	if (ncores > nr_cpu_ids) { +		pr_warn("SMP: %u cores greater than maximum (%u), clipping\n", +			ncores, nr_cpu_ids); +		ncores = nr_cpu_ids; +	} + +	for (i = 0; i < ncores; i++) +		set_cpu_possible(i, true); +} + +static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) +{ +	int i; + +	exynos_sysram_init(); + +	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) +		scu_enable(scu_base_addr()); + +	/* +	 * Write the address of secondary startup into the +	 * system-wide flags register. The boot monitor waits +	 * until it receives a soft interrupt, and then the +	 * secondary CPU branches to this address. +	 * +	 * Try using firmware operation first and fall back to +	 * boot register if it fails. +	 */ +	for (i = 1; i < max_cpus; ++i) { +		unsigned long boot_addr; +		u32 mpidr; +		u32 core_id; +		int ret; + +		mpidr = cpu_logical_map(i); +		core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0); +		boot_addr = virt_to_phys(exynos4_secondary_startup); + +		ret = call_firmware_op(set_cpu_boot_addr, core_id, boot_addr); +		if (ret && ret != -ENOSYS) +			break; +		if (ret == -ENOSYS) { +			void __iomem *boot_reg = cpu_boot_reg(core_id); + +			if (IS_ERR(boot_reg)) +				break; +			__raw_writel(boot_addr, cpu_boot_reg(core_id)); +		} +	} +} + +struct smp_operations exynos_smp_ops __initdata = { +	.smp_init_cpus		= exynos_smp_init_cpus, +	.smp_prepare_cpus	= exynos_smp_prepare_cpus, +	.smp_secondary_init	= exynos_secondary_init, +	.smp_boot_secondary	= exynos_boot_secondary, +#ifdef CONFIG_HOTPLUG_CPU +	.cpu_die		= exynos_cpu_die, +#endif +}; diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c new file mode 100644 index 00000000000..202ca73e49c --- /dev/null +++ b/arch/arm/mach-exynos/pm.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * EXYNOS - 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/cpu_pm.h> +#include <linux/io.h> +#include <linux/irqchip/arm-gic.h> +#include <linux/err.h> +#include <linux/clk.h> + +#include <asm/cacheflush.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/smp_scu.h> +#include <asm/suspend.h> + +#include <plat/pm-common.h> +#include <plat/pll.h> +#include <plat/regs-srom.h> + +#include <mach/map.h> + +#include "common.h" +#include "regs-pmu.h" + +/** + * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping + * @hwirq: Hardware IRQ signal of the GIC + * @mask: Mask in PMU wake-up mask register + */ +struct exynos_wkup_irq { +	unsigned int hwirq; +	u32 mask; +}; + +static struct sleep_save exynos5_sys_save[] = { +	SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), +}; + +static struct sleep_save exynos_core_save[] = { +	/* 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), +}; + +/* + * GIC wake-up support + */ + +static u32 exynos_irqwake_intmask = 0xffffffff; + +static const struct exynos_wkup_irq exynos4_wkup_irq[] = { +	{ 76, BIT(1) }, /* RTC alarm */ +	{ 77, BIT(2) }, /* RTC tick */ +	{ /* sentinel */ }, +}; + +static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { +	{ 75, BIT(1) }, /* RTC alarm */ +	{ 76, BIT(2) }, /* RTC tick */ +	{ /* sentinel */ }, +}; + +static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) +{ +	const struct exynos_wkup_irq *wkup_irq; + +	if (soc_is_exynos5250()) +		wkup_irq = exynos5250_wkup_irq; +	else +		wkup_irq = exynos4_wkup_irq; + +	while (wkup_irq->mask) { +		if (wkup_irq->hwirq == data->hwirq) { +			if (!state) +				exynos_irqwake_intmask |= wkup_irq->mask; +			else +				exynos_irqwake_intmask &= ~wkup_irq->mask; +			return 0; +		} +		++wkup_irq; +	} + +	return -ENOENT; +} + +/** + * exynos_core_power_down : power down the specified cpu + * @cpu : the cpu to power down + * + * Power down the specified cpu. The sequence must be finished by a + * call to cpu_do_idle() + * + */ +void exynos_cpu_power_down(int cpu) +{ +	__raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); +} + +/** + * exynos_cpu_power_up : power up the specified cpu + * @cpu : the cpu to power up + * + * Power up the specified cpu + */ +void exynos_cpu_power_up(int cpu) +{ +	__raw_writel(S5P_CORE_LOCAL_PWR_EN, +		     EXYNOS_ARM_CORE_CONFIGURATION(cpu)); +} + +/** + * exynos_cpu_power_state : returns the power state of the cpu + * @cpu : the cpu to retrieve the power state from + * + */ +int exynos_cpu_power_state(int cpu) +{ +	return (__raw_readl(EXYNOS_ARM_CORE_STATUS(cpu)) & +			S5P_CORE_LOCAL_PWR_EN); +} + +/** + * exynos_cluster_power_down : power down the specified cluster + * @cluster : the cluster to power down + */ +void exynos_cluster_power_down(int cluster) +{ +	__raw_writel(0, EXYNOS_COMMON_CONFIGURATION(cluster)); +} + +/** + * exynos_cluster_power_up : power up the specified cluster + * @cluster : the cluster to power up + */ +void exynos_cluster_power_up(int cluster) +{ +	__raw_writel(S5P_CORE_LOCAL_PWR_EN, +		     EXYNOS_COMMON_CONFIGURATION(cluster)); +} + +/** + * exynos_cluster_power_state : returns the power state of the cluster + * @cluster : the cluster to retrieve the power state from + * + */ +int exynos_cluster_power_state(int cluster) +{ +	return (__raw_readl(EXYNOS_COMMON_STATUS(cluster)) & +			S5P_CORE_LOCAL_PWR_EN); +} + +#define EXYNOS_BOOT_VECTOR_ADDR	(samsung_rev() == EXYNOS4210_REV_1_1 ? \ +			S5P_INFORM7 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ +			(sysram_base_addr + 0x24) : S5P_INFORM0)) +#define EXYNOS_BOOT_VECTOR_FLAG	(samsung_rev() == EXYNOS4210_REV_1_1 ? \ +			S5P_INFORM6 : (samsung_rev() == EXYNOS4210_REV_1_0 ? \ +			(sysram_base_addr + 0x20) : S5P_INFORM1)) + +#define S5P_CHECK_AFTR  0xFCBA0D10 +#define S5P_CHECK_SLEEP 0x00000BAD + +/* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */ +static void exynos_set_wakeupmask(long mask) +{ +	__raw_writel(mask, S5P_WAKEUP_MASK); +} + +static void exynos_cpu_set_boot_vector(long flags) +{ +	__raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); +	__raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); +} + +void exynos_enter_aftr(void) +{ +	exynos_set_wakeupmask(0x0000ff3e); +	exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); +	/* Set value of power down register for aftr mode */ +	exynos_sys_powerdown_conf(SYS_AFTR); +} + +/* For Cortex-A9 Diagnostic and Power control register */ +static unsigned int save_arm_register[2]; + +static void exynos_cpu_save_register(void) +{ +	unsigned long tmp; + +	/* 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; +} + +static void exynos_cpu_restore_register(void) +{ +	unsigned long tmp; + +	/* 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"); +} + +static int exynos_cpu_suspend(unsigned long arg) +{ +#ifdef CONFIG_CACHE_L2X0 +	outer_flush_all(); +#endif + +	if (soc_is_exynos5250()) +		flush_cache_all(); + +	/* issue the standby signal into the pm unit. */ +	cpu_do_idle(); + +	pr_info("Failed to suspend the system\n"); +	return 1; /* Aborting suspend */ +} + +static void exynos_pm_prepare(void) +{ +	unsigned int tmp; + +	/* Set wake-up mask registers */ +	__raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); +	__raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); + +	s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + +	if (soc_is_exynos5250()) { +		s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); +		/* Disable USE_RETENTION of JPEG_MEM_OPTION */ +		tmp = __raw_readl(EXYNOS5_JPEG_MEM_OPTION); +		tmp &= ~EXYNOS5_OPTION_USE_RETENTION; +		__raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION); +	} + +	/* Set value of power down register for sleep mode */ + +	exynos_sys_powerdown_conf(SYS_SLEEP); +	__raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); + +	/* ensure at least INFORM0 has the resume address */ + +	__raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); +} + +static void exynos_pm_central_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); +} + +static int exynos_pm_suspend(void) +{ +	unsigned long tmp; + +	exynos_pm_central_suspend(); + +	/* Setting SEQ_OPTION register */ + +	tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); +	__raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); + +	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) +		exynos_cpu_save_register(); + +	return 0; +} + +static int exynos_pm_central_resume(void) +{ +	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); +		/* clear the wakeup state register */ +		__raw_writel(0x0, S5P_WAKEUP_STAT); +		/* No need to perform below restore code */ +		return -1; +	} + +	return 0; +} + +static void exynos_pm_resume(void) +{ +	if (exynos_pm_central_resume()) +		goto early_wakeup; + +	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) +		exynos_cpu_restore_register(); + +	/* 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); + +	if (soc_is_exynos5250()) +		s3c_pm_do_restore(exynos5_sys_save, +			ARRAY_SIZE(exynos5_sys_save)); + +	s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); + +	if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) +		scu_enable(S5P_VA_SCU); + +early_wakeup: + +	/* Clear SLEEP mode set in INFORM1 */ +	__raw_writel(0x0, S5P_INFORM1); + +	return; +} + +static struct syscore_ops exynos_pm_syscore_ops = { +	.suspend	= exynos_pm_suspend, +	.resume		= exynos_pm_resume, +}; + +/* + * Suspend Ops + */ + +static int exynos_suspend_enter(suspend_state_t state) +{ +	int ret; + +	s3c_pm_debug_init(); + +	S3C_PMDBG("%s: suspending the system...\n", __func__); + +	S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, +			exynos_irqwake_intmask, exynos_get_eint_wake_mask()); + +	if (exynos_irqwake_intmask == -1U +	    && exynos_get_eint_wake_mask() == -1U) { +		pr_err("%s: No wake-up sources!\n", __func__); +		pr_err("%s: Aborting sleep\n", __func__); +		return -EINVAL; +	} + +	s3c_pm_save_uarts(); +	exynos_pm_prepare(); +	flush_cache_all(); +	s3c_pm_check_store(); + +	ret = cpu_suspend(0, exynos_cpu_suspend); +	if (ret) +		return ret; + +	s3c_pm_restore_uarts(); + +	S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, +			__raw_readl(S5P_WAKEUP_STAT)); + +	s3c_pm_check_restore(); + +	S3C_PMDBG("%s: resuming the system...\n", __func__); + +	return 0; +} + +static int exynos_suspend_prepare(void) +{ +	s3c_pm_check_prepare(); + +	return 0; +} + +static void exynos_suspend_finish(void) +{ +	s3c_pm_check_cleanup(); +} + +static const struct platform_suspend_ops exynos_suspend_ops = { +	.enter		= exynos_suspend_enter, +	.prepare	= exynos_suspend_prepare, +	.finish		= exynos_suspend_finish, +	.valid		= suspend_valid_only_mem, +}; + +static int exynos_cpu_pm_notifier(struct notifier_block *self, +				  unsigned long cmd, void *v) +{ +	int cpu = smp_processor_id(); + +	switch (cmd) { +	case CPU_PM_ENTER: +		if (cpu == 0) { +			exynos_pm_central_suspend(); +			if (read_cpuid_part_number() == ARM_CPU_PART_CORTEX_A9) +				exynos_cpu_save_register(); +		} +		break; + +	case CPU_PM_EXIT: +		if (cpu == 0) { +			if (read_cpuid_part_number() == +					ARM_CPU_PART_CORTEX_A9) { +				scu_enable(S5P_VA_SCU); +				exynos_cpu_restore_register(); +			} +			exynos_pm_central_resume(); +		} +		break; +	} + +	return NOTIFY_OK; +} + +static struct notifier_block exynos_cpu_pm_notifier_block = { +	.notifier_call = exynos_cpu_pm_notifier, +}; + +void __init exynos_pm_init(void) +{ +	u32 tmp; + +	cpu_pm_register_notifier(&exynos_cpu_pm_notifier_block); + +	/* Platform-specific GIC callback */ +	gic_arch_extn.irq_set_wake = exynos_irq_set_wake; + +	/* All wakeup disable */ +	tmp = __raw_readl(S5P_WAKEUP_MASK); +	tmp |= ((0xFF << 8) | (0x1F << 1)); +	__raw_writel(tmp, S5P_WAKEUP_MASK); + +	register_syscore_ops(&exynos_pm_syscore_ops); +	suspend_set_ops(&exynos_suspend_ops); +} diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c new file mode 100644 index 00000000000..797cb134bff --- /dev/null +++ b/arch/arm/mach-exynos/pm_domains.c @@ -0,0 +1,243 @@ +/* + * Exynos Generic power domain support. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Implementation of Exynos specific power domain control which is used in + * conjunction with runtime-pm. Support for both device-tree and non-device-tree + * based power domain support is included. + * + * 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/io.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/pm_domain.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/sched.h> + +#include "regs-pmu.h" + +#define MAX_CLK_PER_DOMAIN	4 + +/* + * Exynos specific wrapper around the generic power domain + */ +struct exynos_pm_domain { +	void __iomem *base; +	char const *name; +	bool is_off; +	struct generic_pm_domain pd; +	struct clk *oscclk; +	struct clk *clk[MAX_CLK_PER_DOMAIN]; +	struct clk *pclk[MAX_CLK_PER_DOMAIN]; +}; + +static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) +{ +	struct exynos_pm_domain *pd; +	void __iomem *base; +	u32 timeout, pwr; +	char *op; + +	pd = container_of(domain, struct exynos_pm_domain, pd); +	base = pd->base; + +	/* Set oscclk before powering off a domain*/ +	if (!power_on) { +		int i; + +		for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { +			if (IS_ERR(pd->clk[i])) +				break; +			if (clk_set_parent(pd->clk[i], pd->oscclk)) +				pr_err("%s: error setting oscclk as parent to clock %d\n", +						pd->name, i); +		} +	} + +	pwr = power_on ? S5P_INT_LOCAL_PWR_EN : 0; +	__raw_writel(pwr, base); + +	/* Wait max 1ms */ +	timeout = 10; + +	while ((__raw_readl(base + 0x4) & S5P_INT_LOCAL_PWR_EN)	!= pwr) { +		if (!timeout) { +			op = (power_on) ? "enable" : "disable"; +			pr_err("Power domain %s %s failed\n", domain->name, op); +			return -ETIMEDOUT; +		} +		timeout--; +		cpu_relax(); +		usleep_range(80, 100); +	} + +	/* Restore clocks after powering on a domain*/ +	if (power_on) { +		int i; + +		for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { +			if (IS_ERR(pd->clk[i])) +				break; +			if (clk_set_parent(pd->clk[i], pd->pclk[i])) +				pr_err("%s: error setting parent to clock%d\n", +						pd->name, i); +		} +	} + +	return 0; +} + +static int exynos_pd_power_on(struct generic_pm_domain *domain) +{ +	return exynos_pd_power(domain, true); +} + +static int exynos_pd_power_off(struct generic_pm_domain *domain) +{ +	return exynos_pd_power(domain, false); +} + +static void exynos_add_device_to_domain(struct exynos_pm_domain *pd, +					 struct device *dev) +{ +	int ret; + +	dev_dbg(dev, "adding to power domain %s\n", pd->pd.name); + +	while (1) { +		ret = pm_genpd_add_device(&pd->pd, dev); +		if (ret != -EAGAIN) +			break; +		cond_resched(); +	} + +	pm_genpd_dev_need_restore(dev, true); +} + +static void exynos_remove_device_from_domain(struct device *dev) +{ +	struct generic_pm_domain *genpd = dev_to_genpd(dev); +	int ret; + +	dev_dbg(dev, "removing from power domain %s\n", genpd->name); + +	while (1) { +		ret = pm_genpd_remove_device(genpd, dev); +		if (ret != -EAGAIN) +			break; +		cond_resched(); +	} +} + +static void exynos_read_domain_from_dt(struct device *dev) +{ +	struct platform_device *pd_pdev; +	struct exynos_pm_domain *pd; +	struct device_node *node; + +	node = of_parse_phandle(dev->of_node, "samsung,power-domain", 0); +	if (!node) +		return; +	pd_pdev = of_find_device_by_node(node); +	if (!pd_pdev) +		return; +	pd = platform_get_drvdata(pd_pdev); +	exynos_add_device_to_domain(pd, dev); +} + +static int exynos_pm_notifier_call(struct notifier_block *nb, +				    unsigned long event, void *data) +{ +	struct device *dev = data; + +	switch (event) { +	case BUS_NOTIFY_BIND_DRIVER: +		if (dev->of_node) +			exynos_read_domain_from_dt(dev); + +		break; + +	case BUS_NOTIFY_UNBOUND_DRIVER: +		exynos_remove_device_from_domain(dev); + +		break; +	} +	return NOTIFY_DONE; +} + +static struct notifier_block platform_nb = { +	.notifier_call = exynos_pm_notifier_call, +}; + +static __init int exynos4_pm_init_power_domain(void) +{ +	struct platform_device *pdev; +	struct device_node *np; + +	for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { +		struct exynos_pm_domain *pd; +		int on, i; +		struct device *dev; + +		pdev = of_find_device_by_node(np); +		dev = &pdev->dev; + +		pd = kzalloc(sizeof(*pd), GFP_KERNEL); +		if (!pd) { +			pr_err("%s: failed to allocate memory for domain\n", +					__func__); +			return -ENOMEM; +		} + +		pd->pd.name = kstrdup(np->name, GFP_KERNEL); +		pd->name = pd->pd.name; +		pd->base = of_iomap(np, 0); +		pd->pd.power_off = exynos_pd_power_off; +		pd->pd.power_on = exynos_pd_power_on; +		pd->pd.of_node = np; + +		pd->oscclk = clk_get(dev, "oscclk"); +		if (IS_ERR(pd->oscclk)) +			goto no_clk; + +		for (i = 0; i < MAX_CLK_PER_DOMAIN; i++) { +			char clk_name[8]; + +			snprintf(clk_name, sizeof(clk_name), "clk%d", i); +			pd->clk[i] = clk_get(dev, clk_name); +			if (IS_ERR(pd->clk[i])) +				break; +			snprintf(clk_name, sizeof(clk_name), "pclk%d", i); +			pd->pclk[i] = clk_get(dev, clk_name); +			if (IS_ERR(pd->pclk[i])) { +				clk_put(pd->clk[i]); +				pd->clk[i] = ERR_PTR(-EINVAL); +				break; +			} +		} + +		if (IS_ERR(pd->clk[0])) +			clk_put(pd->oscclk); + +no_clk: +		platform_set_drvdata(pdev, pd); + +		on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN; + +		pm_genpd_init(&pd->pd, NULL, !on); +	} + +	bus_register_notifier(&platform_bus_type, &platform_nb); + +	return 0; +} +arch_initcall(exynos4_pm_init_power_domain); diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c new file mode 100644 index 00000000000..fb0deda3b3a --- /dev/null +++ b/arch/arm/mach-exynos/pmu.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. + *		http://www.samsung.com/ + * + * EXYNOS - CPU PMU(Power Management Unit) support + * + * 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/io.h> +#include <linux/kernel.h> +#include <linux/bug.h> + +#include "common.h" +#include "regs-pmu.h" + +static const struct exynos_pmu_conf *exynos_pmu_config; + +static const struct exynos_pmu_conf exynos4210_pmu_config[] = { +	/* { .reg = address, .val = { AFTR, LPA, SLEEP } */ +	{ S5P_ARM_CORE0_LOWPWR,			{ 0x0, 0x0, 0x2 } }, +	{ S5P_DIS_IRQ_CORE0,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_CENTRAL0,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_ARM_CORE1_LOWPWR,			{ 0x0, 0x0, 0x2 } }, +	{ S5P_DIS_IRQ_CORE1,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_CENTRAL1,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_ARM_COMMON_LOWPWR,		{ 0x0, 0x0, 0x2 } }, +	{ S5P_L2_0_LOWPWR,			{ 0x2, 0x2, 0x3 } }, +	{ S5P_L2_1_LOWPWR,			{ 0x2, 0x2, 0x3 } }, +	{ S5P_CMU_ACLKSTOP_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_SCLKSTOP_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_LOWPWR,			{ 0x1, 0x1, 0x0 } }, +	{ S5P_APLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_MPLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_VPLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_EPLL_SYSCLK_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR,	{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_GPSALIVE_LOWPWR,	{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_CAM_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_TV_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_MFC_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_G3D_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_LCD0_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_LCD1_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_MAUDIO_LOWPWR,	{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_CLKSTOP_GPS_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_CAM_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_TV_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_MFC_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_G3D_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_LCD0_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_LCD1_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_MAUDIO_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_GPS_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_TOP_BUS_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_TOP_RETENTION_LOWPWR,		{ 0x1, 0x0, 0x1 } }, +	{ S5P_TOP_PWR_LOWPWR,			{ 0x3, 0x0, 0x3 } }, +	{ S5P_LOGIC_RESET_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_ONENAND_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_MODIMIF_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_G2D_ACP_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_USBOTG_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_HSMMC_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_CSSYS_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_SECSS_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_PCIE_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_SATA_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_DRAM_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_MAUDIO_LOWPWR,	{ 0x1, 0x1, 0x0 } }, +	{ S5P_PAD_RETENTION_GPIO_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_UART_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_MMCA_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_MMCB_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_EBIA_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_EBIB_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_ISOLATION_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_ALV_SEL_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_XUSBXTI_LOWPWR,			{ 0x1, 0x1, 0x0 } }, +	{ S5P_XXTI_LOWPWR,			{ 0x1, 0x1, 0x0 } }, +	{ S5P_EXT_REGULATOR_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_GPIO_MODE_LOWPWR,			{ 0x1, 0x0, 0x0 } }, +	{ S5P_GPIO_MODE_MAUDIO_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CAM_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_TV_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_MFC_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_G3D_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_LCD0_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_LCD1_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_MAUDIO_LOWPWR,			{ 0x7, 0x7, 0x0 } }, +	{ S5P_GPS_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_GPS_ALIVE_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ PMU_TABLE_END,}, +}; + +static const struct exynos_pmu_conf exynos4x12_pmu_config[] = { +	{ S5P_ARM_CORE0_LOWPWR,			{ 0x0, 0x0, 0x2 } }, +	{ S5P_DIS_IRQ_CORE0,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_CENTRAL0,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_ARM_CORE1_LOWPWR,			{ 0x0, 0x0, 0x2 } }, +	{ S5P_DIS_IRQ_CORE1,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_CENTRAL1,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_ISP_ARM_LOWPWR,			{ 0x1, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR,	{ 0x0, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR,	{ 0x0, 0x0, 0x0 } }, +	{ S5P_ARM_COMMON_LOWPWR,		{ 0x0, 0x0, 0x2 } }, +	{ S5P_L2_0_LOWPWR,			{ 0x0, 0x0, 0x3 } }, +	/* XXX_OPTION register should be set other field */ +	{ S5P_ARM_L2_0_OPTION,			{ 0x10, 0x10, 0x0 } }, +	{ S5P_L2_1_LOWPWR,			{ 0x0, 0x0, 0x3 } }, +	{ S5P_ARM_L2_1_OPTION,			{ 0x10, 0x10, 0x0 } }, +	{ S5P_CMU_ACLKSTOP_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_SCLKSTOP_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_LOWPWR,			{ 0x1, 0x1, 0x0 } }, +	{ S5P_DRAM_FREQ_DOWN_LOWPWR,		{ 0x1, 0x1, 0x1 } }, +	{ S5P_DDRPHY_DLLOFF_LOWPWR,		{ 0x1, 0x1, 0x1 } }, +	{ S5P_LPDDR_PHY_DLL_LOCK_LOWPWR,	{ 0x1, 0x1, 0x1 } }, +	{ S5P_CMU_ACLKSTOP_COREBLK_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_SCLKSTOP_COREBLK_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_COREBLK_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_APLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_MPLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_VPLL_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_EPLL_SYSCLK_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_MPLLUSER_SYSCLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_GPSALIVE_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_CAM_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_TV_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_MFC_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_G3D_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_LCD0_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_ISP_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_MAUDIO_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_CLKSTOP_GPS_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_CAM_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_TV_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_MFC_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_G3D_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_LCD0_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_ISP_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_RESET_MAUDIO_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_CMU_RESET_GPS_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_TOP_BUS_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_TOP_RETENTION_LOWPWR,		{ 0x1, 0x0, 0x1 } }, +	{ S5P_TOP_PWR_LOWPWR,			{ 0x3, 0x0, 0x3 } }, +	{ S5P_TOP_BUS_COREBLK_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_TOP_RETENTION_COREBLK_LOWPWR,	{ 0x1, 0x0, 0x1 } }, +	{ S5P_TOP_PWR_COREBLK_LOWPWR,		{ 0x3, 0x0, 0x3 } }, +	{ S5P_LOGIC_RESET_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_OSCCLK_GATE_LOWPWR,		{ 0x1, 0x0, 0x1 } }, +	{ S5P_LOGIC_RESET_COREBLK_LOWPWR,	{ 0x1, 0x1, 0x0 } }, +	{ S5P_OSCCLK_GATE_COREBLK_LOWPWR,	{ 0x1, 0x0, 0x1 } }, +	{ S5P_ONENAND_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_ONENAND_MEM_OPTION,		{ 0x10, 0x10, 0x0 } }, +	{ S5P_HSI_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_HSI_MEM_OPTION,			{ 0x10, 0x10, 0x0 } }, +	{ S5P_G2D_ACP_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_G2D_ACP_MEM_OPTION,		{ 0x10, 0x10, 0x0 } }, +	{ S5P_USBOTG_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_USBOTG_MEM_OPTION,		{ 0x10, 0x10, 0x0 } }, +	{ S5P_HSMMC_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_HSMMC_MEM_OPTION,			{ 0x10, 0x10, 0x0 } }, +	{ S5P_CSSYS_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_CSSYS_MEM_OPTION,			{ 0x10, 0x10, 0x0 } }, +	{ S5P_SECSS_MEM_LOWPWR,			{ 0x3, 0x0, 0x0 } }, +	{ S5P_SECSS_MEM_OPTION,			{ 0x10, 0x10, 0x0 } }, +	{ S5P_ROTATOR_MEM_LOWPWR,		{ 0x3, 0x0, 0x0 } }, +	{ S5P_ROTATOR_MEM_OPTION,		{ 0x10, 0x10, 0x0 } }, +	{ S5P_PAD_RETENTION_DRAM_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_MAUDIO_LOWPWR,	{ 0x1, 0x1, 0x0 } }, +	{ S5P_PAD_RETENTION_GPIO_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_UART_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_MMCA_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_MMCB_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_EBIA_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_EBIB_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_GPIO_COREBLK_LOWPWR,{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_ISOLATION_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_ISOLATION_COREBLK_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_PAD_RETENTION_ALV_SEL_LOWPWR,	{ 0x1, 0x0, 0x0 } }, +	{ S5P_XUSBXTI_LOWPWR,			{ 0x1, 0x1, 0x0 } }, +	{ S5P_XXTI_LOWPWR,			{ 0x1, 0x1, 0x0 } }, +	{ S5P_EXT_REGULATOR_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_GPIO_MODE_LOWPWR,			{ 0x1, 0x0, 0x0 } }, +	{ S5P_GPIO_MODE_COREBLK_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_GPIO_MODE_MAUDIO_LOWPWR,		{ 0x1, 0x1, 0x0 } }, +	{ S5P_TOP_ASB_RESET_LOWPWR,		{ 0x1, 0x1, 0x1 } }, +	{ S5P_TOP_ASB_ISOLATION_LOWPWR,		{ 0x1, 0x0, 0x1 } }, +	{ S5P_CAM_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_TV_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_MFC_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_G3D_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_LCD0_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_ISP_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_MAUDIO_LOWPWR,			{ 0x7, 0x7, 0x0 } }, +	{ S5P_GPS_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_GPS_ALIVE_LOWPWR,			{ 0x7, 0x0, 0x0 } }, +	{ S5P_CMU_SYSCLK_ISP_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ S5P_CMU_SYSCLK_GPS_LOWPWR,		{ 0x1, 0x0, 0x0 } }, +	{ PMU_TABLE_END,}, +}; + +static const struct exynos_pmu_conf exynos4412_pmu_config[] = { +	{ S5P_ARM_CORE2_LOWPWR,			{ 0x0, 0x0, 0x2 } }, +	{ S5P_DIS_IRQ_CORE2,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_CENTRAL2,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_ARM_CORE3_LOWPWR,			{ 0x0, 0x0, 0x2 } }, +	{ S5P_DIS_IRQ_CORE3,			{ 0x0, 0x0, 0x0 } }, +	{ S5P_DIS_IRQ_CENTRAL3,			{ 0x0, 0x0, 0x0 } }, +	{ PMU_TABLE_END,}, +}; + +static const struct exynos_pmu_conf exynos5250_pmu_config[] = { +	/* { .reg = address, .val = { AFTR, LPA, SLEEP } */ +	{ EXYNOS5_ARM_CORE0_SYS_PWR_REG,		{ 0x0, 0x0, 0x2} }, +	{ EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} }, +	{ EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} }, +	{ EXYNOS5_ARM_CORE1_SYS_PWR_REG,		{ 0x0, 0x0, 0x2} }, +	{ EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} }, +	{ EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} }, +	{ EXYNOS5_FSYS_ARM_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_DIS_IRQ_FSYS_ARM_CENTRAL_SYS_PWR_REG,	{ 0x1, 0x1, 0x1} }, +	{ EXYNOS5_ISP_ARM_SYS_PWR_REG,			{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} }, +	{ EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG,	{ 0x0, 0x0, 0x0} }, +	{ EXYNOS5_ARM_COMMON_SYS_PWR_REG,		{ 0x0, 0x0, 0x2} }, +	{ EXYNOS5_ARM_L2_SYS_PWR_REG,			{ 0x3, 0x3, 0x3} }, +	{ EXYNOS5_ARM_L2_OPTION,			{ 0x10, 0x10, 0x0 } }, +	{ EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG,		{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG,		{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_CMU_RESET_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG,	{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG,	{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG,		{ 0x1, 0x1, 0x1} }, +	{ EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG,		{ 0x1, 0x1, 0x1} }, +	{ EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG,		{ 0x1, 0x1, 0x1} }, +	{ EXYNOS5_APLL_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_TOP_BUS_SYS_PWR_REG,			{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_TOP_RETENTION_SYS_PWR_REG,		{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_TOP_PWR_SYS_PWR_REG,			{ 0x3, 0x0, 0x3} }, +	{ EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG,	{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x3} }, +	{ EXYNOS5_LOGIC_RESET_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_OSCCLK_GATE_SYS_PWR_REG,		{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG,	{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG,	{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_USBOTG_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_G2D_MEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_USBDRD_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_SDMMC_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_CSSYS_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_SECSS_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_ROTATOR_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_INTRAM_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_INTROM_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_JPEG_MEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_HSI_MEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_MCUIOP_MEM_SYS_PWR_REG,		{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_SATA_MEM_SYS_PWR_REG,			{ 0x3, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG,	{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_GPIO_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_UART_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_MMCA_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_MMCB_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_EBIA_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_EBIB_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_SPI_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_ISOLATION_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_XUSBXTI_SYS_PWR_REG,			{ 0x1, 0x1, 0x1} }, +	{ EXYNOS5_XXTI_SYS_PWR_REG,			{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_EXT_REGULATOR_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_GPIO_MODE_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG,		{ 0x1, 0x1, 0x1} }, +	{ EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG,	{ 0x1, 0x0, 0x1} }, +	{ EXYNOS5_GSCL_SYS_PWR_REG,			{ 0x7, 0x0, 0x0} }, +	{ EXYNOS5_ISP_SYS_PWR_REG,			{ 0x7, 0x0, 0x0} }, +	{ EXYNOS5_MFC_SYS_PWR_REG,			{ 0x7, 0x0, 0x0} }, +	{ EXYNOS5_G3D_SYS_PWR_REG,			{ 0x7, 0x0, 0x0} }, +	{ EXYNOS5_DISP1_SYS_PWR_REG,			{ 0x7, 0x0, 0x0} }, +	{ EXYNOS5_MAU_SYS_PWR_REG,			{ 0x7, 0x7, 0x0} }, +	{ EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_CLKSTOP_DISP1_SYS_PWR_REG,	{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_SYSCLK_DISP1_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_SYSCLK_MAU_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_RESET_DISP1_SYS_PWR_REG,		{ 0x1, 0x0, 0x0} }, +	{ EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG,		{ 0x1, 0x1, 0x0} }, +	{ PMU_TABLE_END,}, +}; + +static void __iomem * const exynos5_list_both_cnt_feed[] = { +	EXYNOS5_ARM_CORE0_OPTION, +	EXYNOS5_ARM_CORE1_OPTION, +	EXYNOS5_ARM_COMMON_OPTION, +	EXYNOS5_GSCL_OPTION, +	EXYNOS5_ISP_OPTION, +	EXYNOS5_MFC_OPTION, +	EXYNOS5_G3D_OPTION, +	EXYNOS5_DISP1_OPTION, +	EXYNOS5_MAU_OPTION, +	EXYNOS5_TOP_PWR_OPTION, +	EXYNOS5_TOP_PWR_SYSMEM_OPTION, +}; + +static void __iomem * const exynos5_list_diable_wfi_wfe[] = { +	EXYNOS5_ARM_CORE1_OPTION, +	EXYNOS5_FSYS_ARM_OPTION, +	EXYNOS5_ISP_ARM_OPTION, +}; + +static void exynos5_init_pmu(void) +{ +	unsigned int i; +	unsigned int tmp; + +	/* +	 * Enable both SC_FEEDBACK and SC_COUNTER +	 */ +	for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) { +		tmp = __raw_readl(exynos5_list_both_cnt_feed[i]); +		tmp |= (EXYNOS5_USE_SC_FEEDBACK | +			EXYNOS5_USE_SC_COUNTER); +		__raw_writel(tmp, exynos5_list_both_cnt_feed[i]); +	} + +	/* +	 * SKIP_DEACTIVATE_ACEACP_IN_PWDN_BITFIELD Enable +	 */ +	tmp = __raw_readl(EXYNOS5_ARM_COMMON_OPTION); +	tmp |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; +	__raw_writel(tmp, EXYNOS5_ARM_COMMON_OPTION); + +	/* +	 * Disable WFI/WFE on XXX_OPTION +	 */ +	for (i = 0 ; i < ARRAY_SIZE(exynos5_list_diable_wfi_wfe) ; i++) { +		tmp = __raw_readl(exynos5_list_diable_wfi_wfe[i]); +		tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | +			 EXYNOS5_OPTION_USE_STANDBYWFI); +		__raw_writel(tmp, exynos5_list_diable_wfi_wfe[i]); +	} +} + +void exynos_sys_powerdown_conf(enum sys_powerdown mode) +{ +	unsigned int i; + +	if (soc_is_exynos5250()) +		exynos5_init_pmu(); + +	for (i = 0; (exynos_pmu_config[i].reg != PMU_TABLE_END) ; i++) +		__raw_writel(exynos_pmu_config[i].val[mode], +				exynos_pmu_config[i].reg); + +	if (soc_is_exynos4412()) { +		for (i = 0; exynos4412_pmu_config[i].reg != PMU_TABLE_END ; i++) +			__raw_writel(exynos4412_pmu_config[i].val[mode], +				exynos4412_pmu_config[i].reg); +	} +} + +static int __init exynos_pmu_init(void) +{ +	unsigned int value; + +	exynos_pmu_config = exynos4210_pmu_config; + +	if (soc_is_exynos4210()) { +		exynos_pmu_config = exynos4210_pmu_config; +		pr_info("EXYNOS4210 PMU Initialize\n"); +	} else if (soc_is_exynos4212() || soc_is_exynos4412()) { +		exynos_pmu_config = exynos4x12_pmu_config; +		pr_info("EXYNOS4x12 PMU Initialize\n"); +	} else if (soc_is_exynos5250()) { +		/* +		 * When SYS_WDTRESET is set, watchdog timer reset request +		 * is ignored by power management unit. +		 */ +		value = __raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); +		value &= ~EXYNOS5_SYS_WDTRESET; +		__raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); + +		value = __raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); +		value &= ~EXYNOS5_SYS_WDTRESET; +		__raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); + +		exynos_pmu_config = exynos5250_pmu_config; +		pr_info("EXYNOS5250 PMU Initialize\n"); +	} else { +		pr_info("EXYNOS: PMU not supported\n"); +	} + +	return 0; +} +arch_initcall(exynos_pmu_init); diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h new file mode 100644 index 00000000000..1d13b08708f --- /dev/null +++ b/arch/arm/mach-exynos/regs-pmu.h @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2010-2012 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * EXYNOS - Power management unit definition + * + * 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. +*/ + +#ifndef __ASM_ARCH_REGS_PMU_H +#define __ASM_ARCH_REGS_PMU_H __FILE__ + +#include <mach/map.h> + +#define S5P_PMUREG(x)				(S5P_VA_PMU + (x)) +#define S5P_SYSREG(x)				(S3C_VA_SYS + (x)) + +#define S5P_CENTRAL_SEQ_CONFIGURATION		S5P_PMUREG(0x0200) + +#define S5P_CENTRAL_LOWPWR_CFG			(1 << 16) + +#define S5P_CENTRAL_SEQ_OPTION			S5P_PMUREG(0x0208) + +#define S5P_USE_STANDBY_WFI0			(1 << 16) +#define S5P_USE_STANDBY_WFE0			(1 << 24) + +#define EXYNOS_SWRESET				S5P_PMUREG(0x0400) +#define EXYNOS5440_SWRESET			S5P_PMUREG(0x00C4) + +#define S5P_WAKEUP_STAT				S5P_PMUREG(0x0600) +#define S5P_EINT_WAKEUP_MASK			S5P_PMUREG(0x0604) +#define S5P_WAKEUP_MASK				S5P_PMUREG(0x0608) + +#define S5P_INFORM0				S5P_PMUREG(0x0800) +#define S5P_INFORM1				S5P_PMUREG(0x0804) +#define S5P_INFORM5				S5P_PMUREG(0x0814) +#define S5P_INFORM6				S5P_PMUREG(0x0818) +#define S5P_INFORM7				S5P_PMUREG(0x081C) +#define S5P_PMU_SPARE3				S5P_PMUREG(0x090C) + +#define S5P_ARM_CORE0_LOWPWR			S5P_PMUREG(0x1000) +#define S5P_DIS_IRQ_CORE0			S5P_PMUREG(0x1004) +#define S5P_DIS_IRQ_CENTRAL0			S5P_PMUREG(0x1008) +#define S5P_ARM_CORE1_LOWPWR			S5P_PMUREG(0x1010) +#define S5P_DIS_IRQ_CORE1			S5P_PMUREG(0x1014) +#define S5P_DIS_IRQ_CENTRAL1			S5P_PMUREG(0x1018) +#define S5P_ARM_COMMON_LOWPWR			S5P_PMUREG(0x1080) +#define S5P_L2_0_LOWPWR				S5P_PMUREG(0x10C0) +#define S5P_L2_1_LOWPWR				S5P_PMUREG(0x10C4) +#define S5P_CMU_ACLKSTOP_LOWPWR			S5P_PMUREG(0x1100) +#define S5P_CMU_SCLKSTOP_LOWPWR			S5P_PMUREG(0x1104) +#define S5P_CMU_RESET_LOWPWR			S5P_PMUREG(0x110C) +#define S5P_APLL_SYSCLK_LOWPWR			S5P_PMUREG(0x1120) +#define S5P_MPLL_SYSCLK_LOWPWR			S5P_PMUREG(0x1124) +#define S5P_VPLL_SYSCLK_LOWPWR			S5P_PMUREG(0x1128) +#define S5P_EPLL_SYSCLK_LOWPWR			S5P_PMUREG(0x112C) +#define S5P_CMU_CLKSTOP_GPS_ALIVE_LOWPWR	S5P_PMUREG(0x1138) +#define S5P_CMU_RESET_GPSALIVE_LOWPWR		S5P_PMUREG(0x113C) +#define S5P_CMU_CLKSTOP_CAM_LOWPWR		S5P_PMUREG(0x1140) +#define S5P_CMU_CLKSTOP_TV_LOWPWR		S5P_PMUREG(0x1144) +#define S5P_CMU_CLKSTOP_MFC_LOWPWR		S5P_PMUREG(0x1148) +#define S5P_CMU_CLKSTOP_G3D_LOWPWR		S5P_PMUREG(0x114C) +#define S5P_CMU_CLKSTOP_LCD0_LOWPWR		S5P_PMUREG(0x1150) +#define S5P_CMU_CLKSTOP_MAUDIO_LOWPWR		S5P_PMUREG(0x1158) +#define S5P_CMU_CLKSTOP_GPS_LOWPWR		S5P_PMUREG(0x115C) +#define S5P_CMU_RESET_CAM_LOWPWR		S5P_PMUREG(0x1160) +#define S5P_CMU_RESET_TV_LOWPWR			S5P_PMUREG(0x1164) +#define S5P_CMU_RESET_MFC_LOWPWR		S5P_PMUREG(0x1168) +#define S5P_CMU_RESET_G3D_LOWPWR		S5P_PMUREG(0x116C) +#define S5P_CMU_RESET_LCD0_LOWPWR		S5P_PMUREG(0x1170) +#define S5P_CMU_RESET_MAUDIO_LOWPWR		S5P_PMUREG(0x1178) +#define S5P_CMU_RESET_GPS_LOWPWR		S5P_PMUREG(0x117C) +#define S5P_TOP_BUS_LOWPWR			S5P_PMUREG(0x1180) +#define S5P_TOP_RETENTION_LOWPWR		S5P_PMUREG(0x1184) +#define S5P_TOP_PWR_LOWPWR			S5P_PMUREG(0x1188) +#define S5P_LOGIC_RESET_LOWPWR			S5P_PMUREG(0x11A0) +#define S5P_ONENAND_MEM_LOWPWR			S5P_PMUREG(0x11C0) +#define S5P_G2D_ACP_MEM_LOWPWR			S5P_PMUREG(0x11C8) +#define S5P_USBOTG_MEM_LOWPWR			S5P_PMUREG(0x11CC) +#define S5P_HSMMC_MEM_LOWPWR			S5P_PMUREG(0x11D0) +#define S5P_CSSYS_MEM_LOWPWR			S5P_PMUREG(0x11D4) +#define S5P_SECSS_MEM_LOWPWR			S5P_PMUREG(0x11D8) +#define S5P_PAD_RETENTION_DRAM_LOWPWR		S5P_PMUREG(0x1200) +#define S5P_PAD_RETENTION_MAUDIO_LOWPWR		S5P_PMUREG(0x1204) +#define S5P_PAD_RETENTION_GPIO_LOWPWR		S5P_PMUREG(0x1220) +#define S5P_PAD_RETENTION_UART_LOWPWR		S5P_PMUREG(0x1224) +#define S5P_PAD_RETENTION_MMCA_LOWPWR		S5P_PMUREG(0x1228) +#define S5P_PAD_RETENTION_MMCB_LOWPWR		S5P_PMUREG(0x122C) +#define S5P_PAD_RETENTION_EBIA_LOWPWR		S5P_PMUREG(0x1230) +#define S5P_PAD_RETENTION_EBIB_LOWPWR		S5P_PMUREG(0x1234) +#define S5P_PAD_RETENTION_ISOLATION_LOWPWR	S5P_PMUREG(0x1240) +#define S5P_PAD_RETENTION_ALV_SEL_LOWPWR	S5P_PMUREG(0x1260) +#define S5P_XUSBXTI_LOWPWR			S5P_PMUREG(0x1280) +#define S5P_XXTI_LOWPWR				S5P_PMUREG(0x1284) +#define S5P_EXT_REGULATOR_LOWPWR		S5P_PMUREG(0x12C0) +#define S5P_GPIO_MODE_LOWPWR			S5P_PMUREG(0x1300) +#define S5P_GPIO_MODE_MAUDIO_LOWPWR		S5P_PMUREG(0x1340) +#define S5P_CAM_LOWPWR				S5P_PMUREG(0x1380) +#define S5P_TV_LOWPWR				S5P_PMUREG(0x1384) +#define S5P_MFC_LOWPWR				S5P_PMUREG(0x1388) +#define S5P_G3D_LOWPWR				S5P_PMUREG(0x138C) +#define S5P_LCD0_LOWPWR				S5P_PMUREG(0x1390) +#define S5P_MAUDIO_LOWPWR			S5P_PMUREG(0x1398) +#define S5P_GPS_LOWPWR				S5P_PMUREG(0x139C) +#define S5P_GPS_ALIVE_LOWPWR			S5P_PMUREG(0x13A0) + +#define EXYNOS_ARM_CORE0_CONFIGURATION		S5P_PMUREG(0x2000) +#define EXYNOS_ARM_CORE_CONFIGURATION(_nr)	\ +			(EXYNOS_ARM_CORE0_CONFIGURATION + (0x80 * (_nr))) +#define EXYNOS_ARM_CORE_STATUS(_nr)		\ +			(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4) + +#define EXYNOS_ARM_COMMON_CONFIGURATION		S5P_PMUREG(0x2500) +#define EXYNOS_COMMON_CONFIGURATION(_nr)	\ +			(EXYNOS_ARM_COMMON_CONFIGURATION + (0x80 * (_nr))) +#define EXYNOS_COMMON_STATUS(_nr)		\ +			(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x4) + +#define S5P_PAD_RET_MAUDIO_OPTION		S5P_PMUREG(0x3028) +#define S5P_PAD_RET_GPIO_OPTION			S5P_PMUREG(0x3108) +#define S5P_PAD_RET_UART_OPTION			S5P_PMUREG(0x3128) +#define S5P_PAD_RET_MMCA_OPTION			S5P_PMUREG(0x3148) +#define S5P_PAD_RET_MMCB_OPTION			S5P_PMUREG(0x3168) +#define S5P_PAD_RET_EBIA_OPTION			S5P_PMUREG(0x3188) +#define S5P_PAD_RET_EBIB_OPTION			S5P_PMUREG(0x31A8) + +#define S5P_CORE_LOCAL_PWR_EN			0x3 +#define S5P_INT_LOCAL_PWR_EN			0x7 + +/* Only for EXYNOS4210 */ +#define S5P_CMU_CLKSTOP_LCD1_LOWPWR	S5P_PMUREG(0x1154) +#define S5P_CMU_RESET_LCD1_LOWPWR	S5P_PMUREG(0x1174) +#define S5P_MODIMIF_MEM_LOWPWR		S5P_PMUREG(0x11C4) +#define S5P_PCIE_MEM_LOWPWR		S5P_PMUREG(0x11E0) +#define S5P_SATA_MEM_LOWPWR		S5P_PMUREG(0x11E4) +#define S5P_LCD1_LOWPWR			S5P_PMUREG(0x1394) + +/* Only for EXYNOS4x12 */ +#define S5P_ISP_ARM_LOWPWR			S5P_PMUREG(0x1050) +#define S5P_DIS_IRQ_ISP_ARM_LOCAL_LOWPWR	S5P_PMUREG(0x1054) +#define S5P_DIS_IRQ_ISP_ARM_CENTRAL_LOWPWR	S5P_PMUREG(0x1058) +#define S5P_CMU_ACLKSTOP_COREBLK_LOWPWR		S5P_PMUREG(0x1110) +#define S5P_CMU_SCLKSTOP_COREBLK_LOWPWR		S5P_PMUREG(0x1114) +#define S5P_CMU_RESET_COREBLK_LOWPWR		S5P_PMUREG(0x111C) +#define S5P_MPLLUSER_SYSCLK_LOWPWR		S5P_PMUREG(0x1130) +#define S5P_CMU_CLKSTOP_ISP_LOWPWR		S5P_PMUREG(0x1154) +#define S5P_CMU_RESET_ISP_LOWPWR		S5P_PMUREG(0x1174) +#define S5P_TOP_BUS_COREBLK_LOWPWR		S5P_PMUREG(0x1190) +#define S5P_TOP_RETENTION_COREBLK_LOWPWR	S5P_PMUREG(0x1194) +#define S5P_TOP_PWR_COREBLK_LOWPWR		S5P_PMUREG(0x1198) +#define S5P_OSCCLK_GATE_LOWPWR			S5P_PMUREG(0x11A4) +#define S5P_LOGIC_RESET_COREBLK_LOWPWR		S5P_PMUREG(0x11B0) +#define S5P_OSCCLK_GATE_COREBLK_LOWPWR		S5P_PMUREG(0x11B4) +#define S5P_HSI_MEM_LOWPWR			S5P_PMUREG(0x11C4) +#define S5P_ROTATOR_MEM_LOWPWR			S5P_PMUREG(0x11DC) +#define S5P_PAD_RETENTION_GPIO_COREBLK_LOWPWR	S5P_PMUREG(0x123C) +#define S5P_PAD_ISOLATION_COREBLK_LOWPWR	S5P_PMUREG(0x1250) +#define S5P_GPIO_MODE_COREBLK_LOWPWR		S5P_PMUREG(0x1320) +#define S5P_TOP_ASB_RESET_LOWPWR		S5P_PMUREG(0x1344) +#define S5P_TOP_ASB_ISOLATION_LOWPWR		S5P_PMUREG(0x1348) +#define S5P_ISP_LOWPWR				S5P_PMUREG(0x1394) +#define S5P_DRAM_FREQ_DOWN_LOWPWR		S5P_PMUREG(0x13B0) +#define S5P_DDRPHY_DLLOFF_LOWPWR		S5P_PMUREG(0x13B4) +#define S5P_CMU_SYSCLK_ISP_LOWPWR		S5P_PMUREG(0x13B8) +#define S5P_CMU_SYSCLK_GPS_LOWPWR		S5P_PMUREG(0x13BC) +#define S5P_LPDDR_PHY_DLL_LOCK_LOWPWR		S5P_PMUREG(0x13C0) + +#define S5P_ARM_L2_0_OPTION			S5P_PMUREG(0x2608) +#define S5P_ARM_L2_1_OPTION			S5P_PMUREG(0x2628) +#define S5P_ONENAND_MEM_OPTION			S5P_PMUREG(0x2E08) +#define S5P_HSI_MEM_OPTION			S5P_PMUREG(0x2E28) +#define S5P_G2D_ACP_MEM_OPTION			S5P_PMUREG(0x2E48) +#define S5P_USBOTG_MEM_OPTION			S5P_PMUREG(0x2E68) +#define S5P_HSMMC_MEM_OPTION			S5P_PMUREG(0x2E88) +#define S5P_CSSYS_MEM_OPTION			S5P_PMUREG(0x2EA8) +#define S5P_SECSS_MEM_OPTION			S5P_PMUREG(0x2EC8) +#define S5P_ROTATOR_MEM_OPTION			S5P_PMUREG(0x2F48) + +/* Only for EXYNOS4412 */ +#define S5P_ARM_CORE2_LOWPWR			S5P_PMUREG(0x1020) +#define S5P_DIS_IRQ_CORE2			S5P_PMUREG(0x1024) +#define S5P_DIS_IRQ_CENTRAL2			S5P_PMUREG(0x1028) +#define S5P_ARM_CORE3_LOWPWR			S5P_PMUREG(0x1030) +#define S5P_DIS_IRQ_CORE3			S5P_PMUREG(0x1034) +#define S5P_DIS_IRQ_CENTRAL3			S5P_PMUREG(0x1038) + +/* For EXYNOS5 */ + +#define EXYNOS5_SYS_I2C_CFG					S5P_SYSREG(0x0234) + +#define EXYNOS5_AUTO_WDTRESET_DISABLE				S5P_PMUREG(0x0408) +#define EXYNOS5_MASK_WDTRESET_REQUEST				S5P_PMUREG(0x040C) + +#define EXYNOS5_SYS_WDTRESET					(1 << 20) + +#define EXYNOS5_ARM_CORE0_SYS_PWR_REG				S5P_PMUREG(0x1000) +#define EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG		S5P_PMUREG(0x1004) +#define EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG		S5P_PMUREG(0x1008) +#define EXYNOS5_ARM_CORE1_SYS_PWR_REG				S5P_PMUREG(0x1010) +#define EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG		S5P_PMUREG(0x1014) +#define EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG		S5P_PMUREG(0x1018) +#define EXYNOS5_FSYS_ARM_SYS_PWR_REG				S5P_PMUREG(0x1040) +#define EXYNOS5_DIS_IRQ_FSYS_ARM_CENTRAL_SYS_PWR_REG		S5P_PMUREG(0x1048) +#define EXYNOS5_ISP_ARM_SYS_PWR_REG				S5P_PMUREG(0x1050) +#define EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG		S5P_PMUREG(0x1054) +#define EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG		S5P_PMUREG(0x1058) +#define EXYNOS5_ARM_COMMON_SYS_PWR_REG				S5P_PMUREG(0x1080) +#define EXYNOS5_ARM_L2_SYS_PWR_REG				S5P_PMUREG(0x10C0) +#define EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG			S5P_PMUREG(0x1100) +#define EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG			S5P_PMUREG(0x1104) +#define EXYNOS5_CMU_RESET_SYS_PWR_REG				S5P_PMUREG(0x110C) +#define EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x1120) +#define EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x1124) +#define EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x112C) +#define EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG			S5P_PMUREG(0x1130) +#define EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG			S5P_PMUREG(0x1134) +#define EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG			S5P_PMUREG(0x1138) +#define EXYNOS5_APLL_SYSCLK_SYS_PWR_REG				S5P_PMUREG(0x1140) +#define EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG				S5P_PMUREG(0x1144) +#define EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG				S5P_PMUREG(0x1148) +#define EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG				S5P_PMUREG(0x114C) +#define EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG				S5P_PMUREG(0x1150) +#define EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG				S5P_PMUREG(0x1154) +#define EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG			S5P_PMUREG(0x1164) +#define EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG			S5P_PMUREG(0x1170) +#define EXYNOS5_TOP_BUS_SYS_PWR_REG				S5P_PMUREG(0x1180) +#define EXYNOS5_TOP_RETENTION_SYS_PWR_REG			S5P_PMUREG(0x1184) +#define EXYNOS5_TOP_PWR_SYS_PWR_REG				S5P_PMUREG(0x1188) +#define EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x1190) +#define EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG		S5P_PMUREG(0x1194) +#define EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x1198) +#define EXYNOS5_LOGIC_RESET_SYS_PWR_REG				S5P_PMUREG(0x11A0) +#define EXYNOS5_OSCCLK_GATE_SYS_PWR_REG				S5P_PMUREG(0x11A4) +#define EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x11B0) +#define EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x11B4) +#define EXYNOS5_USBOTG_MEM_SYS_PWR_REG				S5P_PMUREG(0x11C0) +#define EXYNOS5_G2D_MEM_SYS_PWR_REG				S5P_PMUREG(0x11C8) +#define EXYNOS5_USBDRD_MEM_SYS_PWR_REG				S5P_PMUREG(0x11CC) +#define EXYNOS5_SDMMC_MEM_SYS_PWR_REG				S5P_PMUREG(0x11D0) +#define EXYNOS5_CSSYS_MEM_SYS_PWR_REG				S5P_PMUREG(0x11D4) +#define EXYNOS5_SECSS_MEM_SYS_PWR_REG				S5P_PMUREG(0x11D8) +#define EXYNOS5_ROTATOR_MEM_SYS_PWR_REG				S5P_PMUREG(0x11DC) +#define EXYNOS5_INTRAM_MEM_SYS_PWR_REG				S5P_PMUREG(0x11E0) +#define EXYNOS5_INTROM_MEM_SYS_PWR_REG				S5P_PMUREG(0x11E4) +#define EXYNOS5_JPEG_MEM_SYS_PWR_REG				S5P_PMUREG(0x11E8) +#define EXYNOS5_HSI_MEM_SYS_PWR_REG				S5P_PMUREG(0x11EC) +#define EXYNOS5_MCUIOP_MEM_SYS_PWR_REG				S5P_PMUREG(0x11F4) +#define EXYNOS5_SATA_MEM_SYS_PWR_REG				S5P_PMUREG(0x11FC) +#define EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG			S5P_PMUREG(0x1200) +#define EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG			S5P_PMUREG(0x1204) +#define EXYNOS5_PAD_RETENTION_EFNAND_SYS_PWR_REG		S5P_PMUREG(0x1208) +#define EXYNOS5_PAD_RETENTION_GPIO_SYS_PWR_REG			S5P_PMUREG(0x1220) +#define EXYNOS5_PAD_RETENTION_UART_SYS_PWR_REG			S5P_PMUREG(0x1224) +#define EXYNOS5_PAD_RETENTION_MMCA_SYS_PWR_REG			S5P_PMUREG(0x1228) +#define EXYNOS5_PAD_RETENTION_MMCB_SYS_PWR_REG			S5P_PMUREG(0x122C) +#define EXYNOS5_PAD_RETENTION_EBIA_SYS_PWR_REG			S5P_PMUREG(0x1230) +#define EXYNOS5_PAD_RETENTION_EBIB_SYS_PWR_REG			S5P_PMUREG(0x1234) +#define EXYNOS5_PAD_RETENTION_SPI_SYS_PWR_REG			S5P_PMUREG(0x1238) +#define EXYNOS5_PAD_RETENTION_GPIO_SYSMEM_SYS_PWR_REG		S5P_PMUREG(0x123C) +#define EXYNOS5_PAD_ISOLATION_SYS_PWR_REG			S5P_PMUREG(0x1240) +#define EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG		S5P_PMUREG(0x1250) +#define EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG				S5P_PMUREG(0x1260) +#define EXYNOS5_XUSBXTI_SYS_PWR_REG				S5P_PMUREG(0x1280) +#define EXYNOS5_XXTI_SYS_PWR_REG				S5P_PMUREG(0x1284) +#define EXYNOS5_EXT_REGULATOR_SYS_PWR_REG			S5P_PMUREG(0x12C0) +#define EXYNOS5_GPIO_MODE_SYS_PWR_REG				S5P_PMUREG(0x1300) +#define EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG			S5P_PMUREG(0x1320) +#define EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG			S5P_PMUREG(0x1340) +#define EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG			S5P_PMUREG(0x1344) +#define EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG			S5P_PMUREG(0x1348) +#define EXYNOS5_GSCL_SYS_PWR_REG				S5P_PMUREG(0x1400) +#define EXYNOS5_ISP_SYS_PWR_REG					S5P_PMUREG(0x1404) +#define EXYNOS5_MFC_SYS_PWR_REG					S5P_PMUREG(0x1408) +#define EXYNOS5_G3D_SYS_PWR_REG					S5P_PMUREG(0x140C) +#define EXYNOS5_DISP1_SYS_PWR_REG				S5P_PMUREG(0x1414) +#define EXYNOS5_MAU_SYS_PWR_REG					S5P_PMUREG(0x1418) +#define EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG			S5P_PMUREG(0x1480) +#define EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG			S5P_PMUREG(0x1484) +#define EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG			S5P_PMUREG(0x1488) +#define EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG			S5P_PMUREG(0x148C) +#define EXYNOS5_CMU_CLKSTOP_DISP1_SYS_PWR_REG			S5P_PMUREG(0x1494) +#define EXYNOS5_CMU_CLKSTOP_MAU_SYS_PWR_REG			S5P_PMUREG(0x1498) +#define EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG			S5P_PMUREG(0x14C0) +#define EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG			S5P_PMUREG(0x14C4) +#define EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG			S5P_PMUREG(0x14C8) +#define EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG			S5P_PMUREG(0x14CC) +#define EXYNOS5_CMU_SYSCLK_DISP1_SYS_PWR_REG			S5P_PMUREG(0x14D4) +#define EXYNOS5_CMU_SYSCLK_MAU_SYS_PWR_REG			S5P_PMUREG(0x14D8) +#define EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG			S5P_PMUREG(0x1580) +#define EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG			S5P_PMUREG(0x1584) +#define EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG			S5P_PMUREG(0x1588) +#define EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG			S5P_PMUREG(0x158C) +#define EXYNOS5_CMU_RESET_DISP1_SYS_PWR_REG			S5P_PMUREG(0x1594) +#define EXYNOS5_CMU_RESET_MAU_SYS_PWR_REG			S5P_PMUREG(0x1598) + +#define EXYNOS5_ARM_CORE0_OPTION				S5P_PMUREG(0x2008) +#define EXYNOS5_ARM_CORE1_OPTION				S5P_PMUREG(0x2088) +#define EXYNOS5_FSYS_ARM_OPTION					S5P_PMUREG(0x2208) +#define EXYNOS5_ISP_ARM_OPTION					S5P_PMUREG(0x2288) +#define EXYNOS5_ARM_COMMON_OPTION				S5P_PMUREG(0x2408) +#define EXYNOS5_ARM_L2_OPTION					S5P_PMUREG(0x2608) +#define EXYNOS5_TOP_PWR_OPTION					S5P_PMUREG(0x2C48) +#define EXYNOS5_TOP_PWR_SYSMEM_OPTION				S5P_PMUREG(0x2CC8) +#define EXYNOS5_JPEG_MEM_OPTION					S5P_PMUREG(0x2F48) +#define EXYNOS5_GSCL_OPTION					S5P_PMUREG(0x4008) +#define EXYNOS5_ISP_OPTION					S5P_PMUREG(0x4028) +#define EXYNOS5_MFC_OPTION					S5P_PMUREG(0x4048) +#define EXYNOS5_G3D_OPTION					S5P_PMUREG(0x4068) +#define EXYNOS5_DISP1_OPTION					S5P_PMUREG(0x40A8) +#define EXYNOS5_MAU_OPTION					S5P_PMUREG(0x40C8) + +#define EXYNOS5_USE_SC_FEEDBACK					(1 << 1) +#define EXYNOS5_USE_SC_COUNTER					(1 << 0) + +#define EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN			(1 << 7) + +#define EXYNOS5_OPTION_USE_STANDBYWFE				(1 << 24) +#define EXYNOS5_OPTION_USE_STANDBYWFI				(1 << 16) + +#define EXYNOS5_OPTION_USE_RETENTION				(1 << 4) + +#define EXYNOS5420_SWRESET_KFC_SEL				0x3 + +#endif /* __ASM_ARCH_REGS_PMU_H */ diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S new file mode 100644 index 00000000000..108a45f4bb6 --- /dev/null +++ b/arch/arm/mach-exynos/sleep.S @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Exynos low-level resume code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/linkage.h> + +#define CPU_MASK	0xff0ffff0 +#define CPU_CORTEX_A9	0x410fc090 + +	/* +	 * The following code is located into the .data section. This is to +	 * allow l2x0_regs_phys to be accessed with a relative load while we +	 * can't rely on any MMU translation. We could have put l2x0_regs_phys +	 * in the .text section as well, but some setups might insist on it to +	 * be truly read-only. (Reference from: arch/arm/kernel/sleep.S) +	 */ +	.data +	.align + +	/* +	 * sleep magic, to allow the bootloader to check for an valid +	 * image to resume to. Must be the first word before the +	 * exynos_cpu_resume entry. +	 */ + +	.word	0x2bedf00d + +	/* +	 * exynos_cpu_resume +	 * +	 * resume code entry for bootloader to call +	 */ + +ENTRY(exynos_cpu_resume) +#ifdef CONFIG_CACHE_L2X0 +	mrc	p15, 0, r0, c0, c0, 0 +	ldr	r1, =CPU_MASK +	and	r0, r0, r1 +	ldr	r1, =CPU_CORTEX_A9 +	cmp	r0, r1 +	bleq	l2c310_early_resume +#endif +	b	cpu_resume +ENDPROC(exynos_cpu_resume) diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h new file mode 100644 index 00000000000..13a1dc8ecbf --- /dev/null +++ b/arch/arm/mach-exynos/smc.h @@ -0,0 +1,31 @@ +/* + *  Copyright (c) 2012 Samsung Electronics. + * + * EXYNOS - SMC Call + * + * 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. + */ + +#ifndef __ASM_ARCH_EXYNOS_SMC_H +#define __ASM_ARCH_EXYNOS_SMC_H + +#define SMC_CMD_INIT		(-1) +#define SMC_CMD_INFO		(-2) +/* For Power Management */ +#define SMC_CMD_SLEEP		(-3) +#define SMC_CMD_CPU1BOOT	(-4) +#define SMC_CMD_CPU0AFTR	(-5) +/* For CP15 Access */ +#define SMC_CMD_C15RESUME	(-11) +/* For L2 Cache Access */ +#define SMC_CMD_L2X0CTRL	(-21) +#define SMC_CMD_L2X0SETUP1	(-22) +#define SMC_CMD_L2X0SETUP2	(-23) +#define SMC_CMD_L2X0INVALL	(-24) +#define SMC_CMD_L2X0DEBUG	(-25) + +extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); + +#endif  | 
