diff options
Diffstat (limited to 'arch/arm/mach-exynos')
-rw-r--r-- | arch/arm/mach-exynos/Kconfig | 11 | ||||
-rw-r--r-- | arch/arm/mach-exynos/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-exynos/common.h | 31 | ||||
-rw-r--r-- | arch/arm/mach-exynos/exynos-pmu.h | 24 | ||||
-rw-r--r-- | arch/arm/mach-exynos/exynos.c | 30 | ||||
-rw-r--r-- | arch/arm/mach-exynos/firmware.c | 67 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mcpm-exynos.c | 32 | ||||
-rw-r--r-- | arch/arm/mach-exynos/platsmp.c | 35 | ||||
-rw-r--r-- | arch/arm/mach-exynos/pm.c | 311 | ||||
-rw-r--r-- | arch/arm/mach-exynos/pmu.c | 669 | ||||
-rw-r--r-- | arch/arm/mach-exynos/regs-pmu.h | 358 | ||||
-rw-r--r-- | arch/arm/mach-exynos/sleep.S | 28 | ||||
-rw-r--r-- | arch/arm/mach-exynos/smc.h | 4 | ||||
-rw-r--r-- | arch/arm/mach-exynos/suspend.c | 566 |
14 files changed, 1800 insertions, 370 deletions
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 2d0240f241b8..b9e3f1c61baf 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig | |||
@@ -24,6 +24,7 @@ menuconfig ARCH_EXYNOS | |||
24 | select PM_GENERIC_DOMAINS if PM_RUNTIME | 24 | select PM_GENERIC_DOMAINS if PM_RUNTIME |
25 | select S5P_DEV_MFC | 25 | select S5P_DEV_MFC |
26 | select SRAM | 26 | select SRAM |
27 | select MFD_SYSCON | ||
27 | help | 28 | help |
28 | Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5) | 29 | Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5) |
29 | 30 | ||
@@ -75,6 +76,11 @@ config SOC_EXYNOS4412 | |||
75 | default y | 76 | default y |
76 | depends on ARCH_EXYNOS4 | 77 | depends on ARCH_EXYNOS4 |
77 | 78 | ||
79 | config SOC_EXYNOS4415 | ||
80 | bool "SAMSUNG EXYNOS4415" | ||
81 | default y | ||
82 | depends on ARCH_EXYNOS4 | ||
83 | |||
78 | config SOC_EXYNOS5250 | 84 | config SOC_EXYNOS5250 |
79 | bool "SAMSUNG EXYNOS5250" | 85 | bool "SAMSUNG EXYNOS5250" |
80 | default y | 86 | default y |
@@ -123,4 +129,9 @@ config EXYNOS5420_MCPM | |||
123 | This is needed to provide CPU and cluster power management | 129 | This is needed to provide CPU and cluster power management |
124 | on Exynos5420 implementing big.LITTLE. | 130 | on Exynos5420 implementing big.LITTLE. |
125 | 131 | ||
132 | config EXYNOS_CPU_SUSPEND | ||
133 | bool | ||
134 | select ARM_CPU_SUSPEND | ||
135 | default PM_SLEEP || ARM_EXYNOS_CPUIDLE | ||
136 | |||
126 | endif | 137 | endif |
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index d634de588d96..bcefb5473ee4 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile | |||
@@ -11,13 +11,15 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree) | |||
11 | 11 | ||
12 | obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o | 12 | obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o |
13 | 13 | ||
14 | obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o | 14 | obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o |
15 | obj-$(CONFIG_PM_SLEEP) += suspend.o | ||
15 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o | 16 | obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o |
16 | 17 | ||
17 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 18 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
18 | 19 | ||
19 | plus_sec := $(call as-instr,.arch_extension sec,+sec) | 20 | plus_sec := $(call as-instr,.arch_extension sec,+sec) |
20 | AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec) | 21 | AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec) |
22 | AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec) | ||
21 | 23 | ||
22 | obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o | 24 | obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o |
23 | CFLAGS_mcpm-exynos.o += -march=armv7-a | 25 | CFLAGS_mcpm-exynos.o += -march=armv7-a |
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 3d3e6af9d015..865f878063cc 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h | |||
@@ -12,7 +12,6 @@ | |||
12 | #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H | 12 | #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H |
13 | #define __ARCH_ARM_MACH_EXYNOS_COMMON_H | 13 | #define __ARCH_ARM_MACH_EXYNOS_COMMON_H |
14 | 14 | ||
15 | #include <linux/reboot.h> | ||
16 | #include <linux/of.h> | 15 | #include <linux/of.h> |
17 | 16 | ||
18 | #define EXYNOS3250_SOC_ID 0xE3472000 | 17 | #define EXYNOS3250_SOC_ID 0xE3472000 |
@@ -111,11 +110,19 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK) | |||
111 | #define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \ | 110 | #define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \ |
112 | soc_is_exynos5420() || soc_is_exynos5800()) | 111 | soc_is_exynos5420() || soc_is_exynos5800()) |
113 | 112 | ||
113 | extern u32 cp15_save_diag; | ||
114 | extern u32 cp15_save_power; | ||
115 | |||
114 | extern void __iomem *sysram_ns_base_addr; | 116 | extern void __iomem *sysram_ns_base_addr; |
115 | extern void __iomem *sysram_base_addr; | 117 | extern void __iomem *sysram_base_addr; |
116 | extern void __iomem *pmu_base_addr; | 118 | extern void __iomem *pmu_base_addr; |
117 | void exynos_sysram_init(void); | 119 | void exynos_sysram_init(void); |
118 | 120 | ||
121 | enum { | ||
122 | FW_DO_IDLE_SLEEP, | ||
123 | FW_DO_IDLE_AFTR, | ||
124 | }; | ||
125 | |||
119 | void exynos_firmware_init(void); | 126 | void exynos_firmware_init(void); |
120 | 127 | ||
121 | extern u32 exynos_get_eint_wake_mask(void); | 128 | extern u32 exynos_get_eint_wake_mask(void); |
@@ -127,32 +134,20 @@ static inline void exynos_pm_init(void) {} | |||
127 | #endif | 134 | #endif |
128 | 135 | ||
129 | extern void exynos_cpu_resume(void); | 136 | extern void exynos_cpu_resume(void); |
137 | extern void exynos_cpu_resume_ns(void); | ||
130 | 138 | ||
131 | extern struct smp_operations exynos_smp_ops; | 139 | extern struct smp_operations exynos_smp_ops; |
132 | 140 | ||
133 | /* PMU(Power Management Unit) support */ | ||
134 | |||
135 | #define PMU_TABLE_END (-1U) | ||
136 | |||
137 | enum sys_powerdown { | ||
138 | SYS_AFTR, | ||
139 | SYS_LPA, | ||
140 | SYS_SLEEP, | ||
141 | NUM_SYS_POWERDOWN, | ||
142 | }; | ||
143 | |||
144 | struct exynos_pmu_conf { | ||
145 | unsigned int offset; | ||
146 | unsigned int val[NUM_SYS_POWERDOWN]; | ||
147 | }; | ||
148 | |||
149 | extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); | ||
150 | extern void exynos_cpu_power_down(int cpu); | 141 | extern void exynos_cpu_power_down(int cpu); |
151 | extern void exynos_cpu_power_up(int cpu); | 142 | extern void exynos_cpu_power_up(int cpu); |
152 | extern int exynos_cpu_power_state(int cpu); | 143 | extern int exynos_cpu_power_state(int cpu); |
153 | extern void exynos_cluster_power_down(int cluster); | 144 | extern void exynos_cluster_power_down(int cluster); |
154 | extern void exynos_cluster_power_up(int cluster); | 145 | extern void exynos_cluster_power_up(int cluster); |
155 | extern int exynos_cluster_power_state(int cluster); | 146 | extern int exynos_cluster_power_state(int cluster); |
147 | extern void exynos_cpu_save_register(void); | ||
148 | extern void exynos_cpu_restore_register(void); | ||
149 | extern void exynos_pm_central_suspend(void); | ||
150 | extern int exynos_pm_central_resume(void); | ||
156 | extern void exynos_enter_aftr(void); | 151 | extern void exynos_enter_aftr(void); |
157 | 152 | ||
158 | extern void s5p_init_cpu(void __iomem *cpuid_addr); | 153 | extern void s5p_init_cpu(void __iomem *cpuid_addr); |
diff --git a/arch/arm/mach-exynos/exynos-pmu.h b/arch/arm/mach-exynos/exynos-pmu.h new file mode 100644 index 000000000000..a2ab0d52b230 --- /dev/null +++ b/arch/arm/mach-exynos/exynos-pmu.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
3 | * http://www.samsung.com | ||
4 | * | ||
5 | * Header for EXYNOS PMU Driver support | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef __EXYNOS_PMU_H | ||
13 | #define __EXYNOS_PMU_H | ||
14 | |||
15 | enum sys_powerdown { | ||
16 | SYS_AFTR, | ||
17 | SYS_LPA, | ||
18 | SYS_SLEEP, | ||
19 | NUM_SYS_POWERDOWN, | ||
20 | }; | ||
21 | |||
22 | extern void exynos_sys_powerdown_conf(enum sys_powerdown mode); | ||
23 | |||
24 | #endif /* __EXYNOS_PMU_H */ | ||
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c index 6de7cf5ef2b2..c13d0837fa8c 100644 --- a/arch/arm/mach-exynos/exynos.c +++ b/arch/arm/mach-exynos/exynos.c | |||
@@ -87,28 +87,6 @@ static struct map_desc exynos5_iodesc[] __initdata = { | |||
87 | }, | 87 | }, |
88 | }; | 88 | }; |
89 | 89 | ||
90 | static void exynos_restart(enum reboot_mode mode, const char *cmd) | ||
91 | { | ||
92 | struct device_node *np; | ||
93 | u32 val = 0x1; | ||
94 | void __iomem *addr = pmu_base_addr + EXYNOS_SWRESET; | ||
95 | |||
96 | if (of_machine_is_compatible("samsung,exynos5440")) { | ||
97 | u32 status; | ||
98 | np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock"); | ||
99 | |||
100 | addr = of_iomap(np, 0) + 0xbc; | ||
101 | status = __raw_readl(addr); | ||
102 | |||
103 | addr = of_iomap(np, 0) + 0xcc; | ||
104 | val = __raw_readl(addr); | ||
105 | |||
106 | val = (val & 0xffff0000) | (status & 0xffff); | ||
107 | } | ||
108 | |||
109 | __raw_writel(val, addr); | ||
110 | } | ||
111 | |||
112 | static struct platform_device exynos_cpuidle = { | 90 | static struct platform_device exynos_cpuidle = { |
113 | .name = "exynos_cpuidle", | 91 | .name = "exynos_cpuidle", |
114 | #ifdef CONFIG_ARM_EXYNOS_CPUIDLE | 92 | #ifdef CONFIG_ARM_EXYNOS_CPUIDLE |
@@ -202,6 +180,7 @@ static const struct of_device_id exynos_dt_pmu_match[] = { | |||
202 | { .compatible = "samsung,exynos4210-pmu" }, | 180 | { .compatible = "samsung,exynos4210-pmu" }, |
203 | { .compatible = "samsung,exynos4212-pmu" }, | 181 | { .compatible = "samsung,exynos4212-pmu" }, |
204 | { .compatible = "samsung,exynos4412-pmu" }, | 182 | { .compatible = "samsung,exynos4412-pmu" }, |
183 | { .compatible = "samsung,exynos4415-pmu" }, | ||
205 | { .compatible = "samsung,exynos5250-pmu" }, | 184 | { .compatible = "samsung,exynos5250-pmu" }, |
206 | { .compatible = "samsung,exynos5260-pmu" }, | 185 | { .compatible = "samsung,exynos5260-pmu" }, |
207 | { .compatible = "samsung,exynos5410-pmu" }, | 186 | { .compatible = "samsung,exynos5410-pmu" }, |
@@ -268,7 +247,10 @@ static void __init exynos_dt_machine_init(void) | |||
268 | exynos_sysram_init(); | 247 | exynos_sysram_init(); |
269 | 248 | ||
270 | if (of_machine_is_compatible("samsung,exynos4210") || | 249 | if (of_machine_is_compatible("samsung,exynos4210") || |
271 | of_machine_is_compatible("samsung,exynos5250")) | 250 | of_machine_is_compatible("samsung,exynos4212") || |
251 | (of_machine_is_compatible("samsung,exynos4412") && | ||
252 | of_machine_is_compatible("samsung,trats2")) || | ||
253 | of_machine_is_compatible("samsung,exynos5250")) | ||
272 | platform_device_register(&exynos_cpuidle); | 254 | platform_device_register(&exynos_cpuidle); |
273 | 255 | ||
274 | platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); | 256 | platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); |
@@ -283,6 +265,7 @@ static char const *exynos_dt_compat[] __initconst = { | |||
283 | "samsung,exynos4210", | 265 | "samsung,exynos4210", |
284 | "samsung,exynos4212", | 266 | "samsung,exynos4212", |
285 | "samsung,exynos4412", | 267 | "samsung,exynos4412", |
268 | "samsung,exynos4415", | ||
286 | "samsung,exynos5", | 269 | "samsung,exynos5", |
287 | "samsung,exynos5250", | 270 | "samsung,exynos5250", |
288 | "samsung,exynos5260", | 271 | "samsung,exynos5260", |
@@ -328,7 +311,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)") | |||
328 | .init_machine = exynos_dt_machine_init, | 311 | .init_machine = exynos_dt_machine_init, |
329 | .init_late = exynos_init_late, | 312 | .init_late = exynos_init_late, |
330 | .dt_compat = exynos_dt_compat, | 313 | .dt_compat = exynos_dt_compat, |
331 | .restart = exynos_restart, | ||
332 | .reserve = exynos_reserve, | 314 | .reserve = exynos_reserve, |
333 | .dt_fixup = exynos_dt_fixup, | 315 | .dt_fixup = exynos_dt_fixup, |
334 | MACHINE_END | 316 | MACHINE_END |
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c index e8797bb78871..766f57d2f029 100644 --- a/arch/arm/mach-exynos/firmware.c +++ b/arch/arm/mach-exynos/firmware.c | |||
@@ -14,16 +14,44 @@ | |||
14 | #include <linux/of.h> | 14 | #include <linux/of.h> |
15 | #include <linux/of_address.h> | 15 | #include <linux/of_address.h> |
16 | 16 | ||
17 | #include <asm/cacheflush.h> | ||
18 | #include <asm/cputype.h> | ||
17 | #include <asm/firmware.h> | 19 | #include <asm/firmware.h> |
20 | #include <asm/suspend.h> | ||
18 | 21 | ||
19 | #include <mach/map.h> | 22 | #include <mach/map.h> |
20 | 23 | ||
21 | #include "common.h" | 24 | #include "common.h" |
22 | #include "smc.h" | 25 | #include "smc.h" |
23 | 26 | ||
24 | static int exynos_do_idle(void) | 27 | #define EXYNOS_SLEEP_MAGIC 0x00000bad |
28 | #define EXYNOS_AFTR_MAGIC 0xfcba0d10 | ||
29 | #define EXYNOS_BOOT_ADDR 0x8 | ||
30 | #define EXYNOS_BOOT_FLAG 0xc | ||
31 | |||
32 | static void exynos_save_cp15(void) | ||
25 | { | 33 | { |
26 | exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); | 34 | /* Save Power control and Diagnostic registers */ |
35 | asm ("mrc p15, 0, %0, c15, c0, 0\n" | ||
36 | "mrc p15, 0, %1, c15, c0, 1\n" | ||
37 | : "=r" (cp15_save_power), "=r" (cp15_save_diag) | ||
38 | : : "cc"); | ||
39 | } | ||
40 | |||
41 | static int exynos_do_idle(unsigned long mode) | ||
42 | { | ||
43 | switch (mode) { | ||
44 | case FW_DO_IDLE_AFTR: | ||
45 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
46 | exynos_save_cp15(); | ||
47 | __raw_writel(virt_to_phys(exynos_cpu_resume_ns), | ||
48 | sysram_ns_base_addr + 0x24); | ||
49 | __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20); | ||
50 | exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0); | ||
51 | break; | ||
52 | case FW_DO_IDLE_SLEEP: | ||
53 | exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); | ||
54 | } | ||
27 | return 0; | 55 | return 0; |
28 | } | 56 | } |
29 | 57 | ||
@@ -69,10 +97,43 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr) | |||
69 | return 0; | 97 | return 0; |
70 | } | 98 | } |
71 | 99 | ||
100 | static int exynos_cpu_suspend(unsigned long arg) | ||
101 | { | ||
102 | flush_cache_all(); | ||
103 | outer_flush_all(); | ||
104 | |||
105 | exynos_smc(SMC_CMD_SLEEP, 0, 0, 0); | ||
106 | |||
107 | pr_info("Failed to suspend the system\n"); | ||
108 | writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); | ||
109 | return 1; | ||
110 | } | ||
111 | |||
112 | static int exynos_suspend(void) | ||
113 | { | ||
114 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
115 | exynos_save_cp15(); | ||
116 | |||
117 | writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); | ||
118 | writel(virt_to_phys(exynos_cpu_resume_ns), | ||
119 | sysram_ns_base_addr + EXYNOS_BOOT_ADDR); | ||
120 | |||
121 | return cpu_suspend(0, exynos_cpu_suspend); | ||
122 | } | ||
123 | |||
124 | static int exynos_resume(void) | ||
125 | { | ||
126 | writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG); | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
72 | static const struct firmware_ops exynos_firmware_ops = { | 131 | static const struct firmware_ops exynos_firmware_ops = { |
73 | .do_idle = exynos_do_idle, | 132 | .do_idle = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_do_idle : NULL, |
74 | .set_cpu_boot_addr = exynos_set_cpu_boot_addr, | 133 | .set_cpu_boot_addr = exynos_set_cpu_boot_addr, |
75 | .cpu_boot = exynos_cpu_boot, | 134 | .cpu_boot = exynos_cpu_boot, |
135 | .suspend = IS_ENABLED(CONFIG_PM_SLEEP) ? exynos_suspend : NULL, | ||
136 | .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL, | ||
76 | }; | 137 | }; |
77 | 138 | ||
78 | void __init exynos_firmware_init(void) | 139 | void __init exynos_firmware_init(void) |
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c index dc9a764a7c37..b0d3c2e876fb 100644 --- a/arch/arm/mach-exynos/mcpm-exynos.c +++ b/arch/arm/mach-exynos/mcpm-exynos.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/of_address.h> | 17 | #include <linux/of_address.h> |
18 | #include <linux/syscore_ops.h> | ||
18 | 19 | ||
19 | #include <asm/cputype.h> | 20 | #include <asm/cputype.h> |
20 | #include <asm/cp15.h> | 21 | #include <asm/cp15.h> |
@@ -30,6 +31,8 @@ | |||
30 | #define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29) | 31 | #define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29) |
31 | #define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30) | 32 | #define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30) |
32 | 33 | ||
34 | static void __iomem *ns_sram_base_addr; | ||
35 | |||
33 | /* | 36 | /* |
34 | * The common v7_exit_coherency_flush API could not be used because of the | 37 | * The common v7_exit_coherency_flush API could not be used because of the |
35 | * Erratum 799270 workaround. This macro is the same as the common one (in | 38 | * Erratum 799270 workaround. This macro is the same as the common one (in |
@@ -318,10 +321,26 @@ static const struct of_device_id exynos_dt_mcpm_match[] = { | |||
318 | {}, | 321 | {}, |
319 | }; | 322 | }; |
320 | 323 | ||
324 | static void exynos_mcpm_setup_entry_point(void) | ||
325 | { | ||
326 | /* | ||
327 | * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr | ||
328 | * as part of secondary_cpu_start(). Let's redirect it to the | ||
329 | * mcpm_entry_point(). This is done during both secondary boot-up as | ||
330 | * well as system resume. | ||
331 | */ | ||
332 | __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */ | ||
333 | __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */ | ||
334 | __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8); | ||
335 | } | ||
336 | |||
337 | static struct syscore_ops exynos_mcpm_syscore_ops = { | ||
338 | .resume = exynos_mcpm_setup_entry_point, | ||
339 | }; | ||
340 | |||
321 | static int __init exynos_mcpm_init(void) | 341 | static int __init exynos_mcpm_init(void) |
322 | { | 342 | { |
323 | struct device_node *node; | 343 | struct device_node *node; |
324 | void __iomem *ns_sram_base_addr; | ||
325 | unsigned int value, i; | 344 | unsigned int value, i; |
326 | int ret; | 345 | int ret; |
327 | 346 | ||
@@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void) | |||
387 | pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i)); | 406 | pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i)); |
388 | } | 407 | } |
389 | 408 | ||
390 | /* | 409 | exynos_mcpm_setup_entry_point(); |
391 | * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr | ||
392 | * as part of secondary_cpu_start(). Let's redirect it to the | ||
393 | * mcpm_entry_point(). | ||
394 | */ | ||
395 | __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */ | ||
396 | __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */ | ||
397 | __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8); | ||
398 | 410 | ||
399 | iounmap(ns_sram_base_addr); | 411 | register_syscore_ops(&exynos_mcpm_syscore_ops); |
400 | 412 | ||
401 | return ret; | 413 | return ret; |
402 | } | 414 | } |
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c index 9c6dd1451136..7a1ebfeeeeb8 100644 --- a/arch/arm/mach-exynos/platsmp.c +++ b/arch/arm/mach-exynos/platsmp.c | |||
@@ -126,6 +126,18 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious) | |||
126 | */ | 126 | */ |
127 | void exynos_cpu_power_down(int cpu) | 127 | void exynos_cpu_power_down(int cpu) |
128 | { | 128 | { |
129 | if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") || | ||
130 | of_machine_is_compatible("samsung,exynos5800"))) { | ||
131 | /* | ||
132 | * Bypass power down for CPU0 during suspend. Check for | ||
133 | * the SYS_PWR_REG value to decide if we are suspending | ||
134 | * the system. | ||
135 | */ | ||
136 | int val = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); | ||
137 | |||
138 | if (!(val & S5P_CORE_LOCAL_PWR_EN)) | ||
139 | return; | ||
140 | } | ||
129 | pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); | 141 | pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu)); |
130 | } | 142 | } |
131 | 143 | ||
@@ -204,6 +216,26 @@ static inline void __iomem *cpu_boot_reg(int cpu) | |||
204 | } | 216 | } |
205 | 217 | ||
206 | /* | 218 | /* |
219 | * Set wake up by local power mode and execute software reset for given core. | ||
220 | * | ||
221 | * Currently this is needed only when booting secondary CPU on Exynos3250. | ||
222 | */ | ||
223 | static void exynos_core_restart(u32 core_id) | ||
224 | { | ||
225 | u32 val; | ||
226 | |||
227 | if (!of_machine_is_compatible("samsung,exynos3250")) | ||
228 | return; | ||
229 | |||
230 | val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id)); | ||
231 | val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG; | ||
232 | pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id)); | ||
233 | |||
234 | pr_info("CPU%u: Software reset\n", core_id); | ||
235 | pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET); | ||
236 | } | ||
237 | |||
238 | /* | ||
207 | * Write pen_release in a way that is guaranteed to be visible to all | 239 | * Write pen_release in a way that is guaranteed to be visible to all |
208 | * observers, irrespective of whether they're taking part in coherency | 240 | * observers, irrespective of whether they're taking part in coherency |
209 | * or not. This is necessary for the hotplug code to work reliably. | 241 | * or not. This is necessary for the hotplug code to work reliably. |
@@ -279,6 +311,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle) | |||
279 | return -ETIMEDOUT; | 311 | return -ETIMEDOUT; |
280 | } | 312 | } |
281 | } | 313 | } |
314 | |||
315 | exynos_core_restart(core_id); | ||
316 | |||
282 | /* | 317 | /* |
283 | * Send the secondary CPU a soft interrupt, thereby causing | 318 | * Send the secondary CPU a soft interrupt, thereby causing |
284 | * the boot monitor to read the system wide flags register, | 319 | * the boot monitor to read the system wide flags register, |
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c index abefacb45976..86f3ecd88f78 100644 --- a/arch/arm/mach-exynos/pm.c +++ b/arch/arm/mach-exynos/pm.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. | 2 | * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. |
3 | * http://www.samsung.com | 3 | * http://www.samsung.com |
4 | * | 4 | * |
5 | * EXYNOS - Power Management support | 5 | * EXYNOS - Power Management support |
@@ -15,109 +15,45 @@ | |||
15 | 15 | ||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/suspend.h> | 17 | #include <linux/suspend.h> |
18 | #include <linux/syscore_ops.h> | ||
19 | #include <linux/cpu_pm.h> | 18 | #include <linux/cpu_pm.h> |
20 | #include <linux/io.h> | 19 | #include <linux/io.h> |
21 | #include <linux/irqchip/arm-gic.h> | ||
22 | #include <linux/err.h> | 20 | #include <linux/err.h> |
23 | #include <linux/clk.h> | ||
24 | 21 | ||
25 | #include <asm/cacheflush.h> | 22 | #include <asm/firmware.h> |
26 | #include <asm/hardware/cache-l2x0.h> | ||
27 | #include <asm/smp_scu.h> | 23 | #include <asm/smp_scu.h> |
28 | #include <asm/suspend.h> | 24 | #include <asm/suspend.h> |
29 | 25 | ||
30 | #include <plat/pm-common.h> | 26 | #include <plat/pm-common.h> |
31 | #include <plat/regs-srom.h> | ||
32 | |||
33 | #include <mach/map.h> | ||
34 | 27 | ||
35 | #include "common.h" | 28 | #include "common.h" |
29 | #include "exynos-pmu.h" | ||
36 | #include "regs-pmu.h" | 30 | #include "regs-pmu.h" |
37 | #include "regs-sys.h" | 31 | #include "regs-sys.h" |
38 | 32 | ||
39 | /** | 33 | static inline void __iomem *exynos_boot_vector_addr(void) |
40 | * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping | ||
41 | * @hwirq: Hardware IRQ signal of the GIC | ||
42 | * @mask: Mask in PMU wake-up mask register | ||
43 | */ | ||
44 | struct exynos_wkup_irq { | ||
45 | unsigned int hwirq; | ||
46 | u32 mask; | ||
47 | }; | ||
48 | |||
49 | static struct sleep_save exynos5_sys_save[] = { | ||
50 | SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), | ||
51 | }; | ||
52 | |||
53 | static struct sleep_save exynos_core_save[] = { | ||
54 | /* SROM side */ | ||
55 | SAVE_ITEM(S5P_SROM_BW), | ||
56 | SAVE_ITEM(S5P_SROM_BC0), | ||
57 | SAVE_ITEM(S5P_SROM_BC1), | ||
58 | SAVE_ITEM(S5P_SROM_BC2), | ||
59 | SAVE_ITEM(S5P_SROM_BC3), | ||
60 | }; | ||
61 | |||
62 | /* | ||
63 | * GIC wake-up support | ||
64 | */ | ||
65 | |||
66 | static u32 exynos_irqwake_intmask = 0xffffffff; | ||
67 | |||
68 | static const struct exynos_wkup_irq exynos4_wkup_irq[] = { | ||
69 | { 76, BIT(1) }, /* RTC alarm */ | ||
70 | { 77, BIT(2) }, /* RTC tick */ | ||
71 | { /* sentinel */ }, | ||
72 | }; | ||
73 | |||
74 | static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { | ||
75 | { 75, BIT(1) }, /* RTC alarm */ | ||
76 | { 76, BIT(2) }, /* RTC tick */ | ||
77 | { /* sentinel */ }, | ||
78 | }; | ||
79 | |||
80 | static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) | ||
81 | { | 34 | { |
82 | const struct exynos_wkup_irq *wkup_irq; | 35 | if (samsung_rev() == EXYNOS4210_REV_1_1) |
83 | 36 | return pmu_base_addr + S5P_INFORM7; | |
84 | if (soc_is_exynos5250()) | 37 | else if (samsung_rev() == EXYNOS4210_REV_1_0) |
85 | wkup_irq = exynos5250_wkup_irq; | 38 | return sysram_base_addr + 0x24; |
86 | else | 39 | return pmu_base_addr + S5P_INFORM0; |
87 | wkup_irq = exynos4_wkup_irq; | ||
88 | |||
89 | while (wkup_irq->mask) { | ||
90 | if (wkup_irq->hwirq == data->hwirq) { | ||
91 | if (!state) | ||
92 | exynos_irqwake_intmask |= wkup_irq->mask; | ||
93 | else | ||
94 | exynos_irqwake_intmask &= ~wkup_irq->mask; | ||
95 | return 0; | ||
96 | } | ||
97 | ++wkup_irq; | ||
98 | } | ||
99 | |||
100 | return -ENOENT; | ||
101 | } | 40 | } |
102 | 41 | ||
103 | #define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \ | 42 | static inline void __iomem *exynos_boot_vector_flag(void) |
104 | pmu_base_addr + S5P_INFORM7 : \ | 43 | { |
105 | (samsung_rev() == EXYNOS4210_REV_1_0 ? \ | 44 | if (samsung_rev() == EXYNOS4210_REV_1_1) |
106 | (sysram_base_addr + 0x24) : \ | 45 | return pmu_base_addr + S5P_INFORM6; |
107 | pmu_base_addr + S5P_INFORM0)) | 46 | else if (samsung_rev() == EXYNOS4210_REV_1_0) |
108 | #define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \ | 47 | return sysram_base_addr + 0x20; |
109 | pmu_base_addr + S5P_INFORM6 : \ | 48 | return pmu_base_addr + S5P_INFORM1; |
110 | (samsung_rev() == EXYNOS4210_REV_1_0 ? \ | 49 | } |
111 | (sysram_base_addr + 0x20) : \ | ||
112 | pmu_base_addr + S5P_INFORM1)) | ||
113 | 50 | ||
114 | #define S5P_CHECK_AFTR 0xFCBA0D10 | 51 | #define S5P_CHECK_AFTR 0xFCBA0D10 |
115 | #define S5P_CHECK_SLEEP 0x00000BAD | ||
116 | 52 | ||
117 | /* For Cortex-A9 Diagnostic and Power control register */ | 53 | /* For Cortex-A9 Diagnostic and Power control register */ |
118 | static unsigned int save_arm_register[2]; | 54 | static unsigned int save_arm_register[2]; |
119 | 55 | ||
120 | static void exynos_cpu_save_register(void) | 56 | void exynos_cpu_save_register(void) |
121 | { | 57 | { |
122 | unsigned long tmp; | 58 | unsigned long tmp; |
123 | 59 | ||
@@ -134,7 +70,7 @@ static void exynos_cpu_save_register(void) | |||
134 | save_arm_register[1] = tmp; | 70 | save_arm_register[1] = tmp; |
135 | } | 71 | } |
136 | 72 | ||
137 | static void exynos_cpu_restore_register(void) | 73 | void exynos_cpu_restore_register(void) |
138 | { | 74 | { |
139 | unsigned long tmp; | 75 | unsigned long tmp; |
140 | 76 | ||
@@ -153,7 +89,7 @@ static void exynos_cpu_restore_register(void) | |||
153 | : "cc"); | 89 | : "cc"); |
154 | } | 90 | } |
155 | 91 | ||
156 | static void exynos_pm_central_suspend(void) | 92 | void exynos_pm_central_suspend(void) |
157 | { | 93 | { |
158 | unsigned long tmp; | 94 | unsigned long tmp; |
159 | 95 | ||
@@ -161,9 +97,13 @@ static void exynos_pm_central_suspend(void) | |||
161 | tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); | 97 | tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION); |
162 | tmp &= ~S5P_CENTRAL_LOWPWR_CFG; | 98 | tmp &= ~S5P_CENTRAL_LOWPWR_CFG; |
163 | pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); | 99 | pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION); |
100 | |||
101 | /* Setting SEQ_OPTION register */ | ||
102 | pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0, | ||
103 | S5P_CENTRAL_SEQ_OPTION); | ||
164 | } | 104 | } |
165 | 105 | ||
166 | static int exynos_pm_central_resume(void) | 106 | int exynos_pm_central_resume(void) |
167 | { | 107 | { |
168 | unsigned long tmp; | 108 | unsigned long tmp; |
169 | 109 | ||
@@ -194,17 +134,26 @@ static void exynos_set_wakeupmask(long mask) | |||
194 | 134 | ||
195 | static void exynos_cpu_set_boot_vector(long flags) | 135 | static void exynos_cpu_set_boot_vector(long flags) |
196 | { | 136 | { |
197 | __raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR); | 137 | __raw_writel(virt_to_phys(exynos_cpu_resume), |
198 | __raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG); | 138 | exynos_boot_vector_addr()); |
139 | __raw_writel(flags, exynos_boot_vector_flag()); | ||
199 | } | 140 | } |
200 | 141 | ||
201 | static int exynos_aftr_finisher(unsigned long flags) | 142 | static int exynos_aftr_finisher(unsigned long flags) |
202 | { | 143 | { |
144 | int ret; | ||
145 | |||
203 | exynos_set_wakeupmask(0x0000ff3e); | 146 | exynos_set_wakeupmask(0x0000ff3e); |
204 | exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); | ||
205 | /* Set value of power down register for aftr mode */ | 147 | /* Set value of power down register for aftr mode */ |
206 | exynos_sys_powerdown_conf(SYS_AFTR); | 148 | exynos_sys_powerdown_conf(SYS_AFTR); |
207 | cpu_do_idle(); | 149 | |
150 | ret = call_firmware_op(do_idle, FW_DO_IDLE_AFTR); | ||
151 | if (ret == -ENOSYS) { | ||
152 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
153 | exynos_cpu_save_register(); | ||
154 | exynos_cpu_set_boot_vector(S5P_CHECK_AFTR); | ||
155 | cpu_do_idle(); | ||
156 | } | ||
208 | 157 | ||
209 | return 1; | 158 | return 1; |
210 | } | 159 | } |
@@ -214,196 +163,16 @@ void exynos_enter_aftr(void) | |||
214 | cpu_pm_enter(); | 163 | cpu_pm_enter(); |
215 | 164 | ||
216 | exynos_pm_central_suspend(); | 165 | exynos_pm_central_suspend(); |
217 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
218 | exynos_cpu_save_register(); | ||
219 | 166 | ||
220 | cpu_suspend(0, exynos_aftr_finisher); | 167 | cpu_suspend(0, exynos_aftr_finisher); |
221 | 168 | ||
222 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { | 169 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { |
223 | scu_enable(S5P_VA_SCU); | 170 | scu_enable(S5P_VA_SCU); |
224 | exynos_cpu_restore_register(); | 171 | if (call_firmware_op(resume) == -ENOSYS) |
172 | exynos_cpu_restore_register(); | ||
225 | } | 173 | } |
226 | 174 | ||
227 | exynos_pm_central_resume(); | 175 | exynos_pm_central_resume(); |
228 | 176 | ||
229 | cpu_pm_exit(); | 177 | cpu_pm_exit(); |
230 | } | 178 | } |
231 | |||
232 | static int exynos_cpu_suspend(unsigned long arg) | ||
233 | { | ||
234 | #ifdef CONFIG_CACHE_L2X0 | ||
235 | outer_flush_all(); | ||
236 | #endif | ||
237 | |||
238 | if (soc_is_exynos5250()) | ||
239 | flush_cache_all(); | ||
240 | |||
241 | /* issue the standby signal into the pm unit. */ | ||
242 | cpu_do_idle(); | ||
243 | |||
244 | pr_info("Failed to suspend the system\n"); | ||
245 | return 1; /* Aborting suspend */ | ||
246 | } | ||
247 | |||
248 | static void exynos_pm_prepare(void) | ||
249 | { | ||
250 | unsigned int tmp; | ||
251 | |||
252 | /* Set wake-up mask registers */ | ||
253 | pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); | ||
254 | pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); | ||
255 | |||
256 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
257 | |||
258 | if (soc_is_exynos5250()) { | ||
259 | s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save)); | ||
260 | /* Disable USE_RETENTION of JPEG_MEM_OPTION */ | ||
261 | tmp = pmu_raw_readl(EXYNOS5_JPEG_MEM_OPTION); | ||
262 | tmp &= ~EXYNOS5_OPTION_USE_RETENTION; | ||
263 | pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION); | ||
264 | } | ||
265 | |||
266 | /* Set value of power down register for sleep mode */ | ||
267 | |||
268 | exynos_sys_powerdown_conf(SYS_SLEEP); | ||
269 | pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); | ||
270 | |||
271 | /* ensure at least INFORM0 has the resume address */ | ||
272 | |||
273 | pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); | ||
274 | } | ||
275 | |||
276 | static int exynos_pm_suspend(void) | ||
277 | { | ||
278 | unsigned long tmp; | ||
279 | |||
280 | exynos_pm_central_suspend(); | ||
281 | |||
282 | /* Setting SEQ_OPTION register */ | ||
283 | |||
284 | tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0); | ||
285 | pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION); | ||
286 | |||
287 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
288 | exynos_cpu_save_register(); | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static void exynos_pm_resume(void) | ||
294 | { | ||
295 | if (exynos_pm_central_resume()) | ||
296 | goto early_wakeup; | ||
297 | |||
298 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
299 | exynos_cpu_restore_register(); | ||
300 | |||
301 | /* For release retention */ | ||
302 | |||
303 | pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION); | ||
304 | pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION); | ||
305 | pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION); | ||
306 | pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION); | ||
307 | pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION); | ||
308 | pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION); | ||
309 | pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION); | ||
310 | |||
311 | if (soc_is_exynos5250()) | ||
312 | s3c_pm_do_restore(exynos5_sys_save, | ||
313 | ARRAY_SIZE(exynos5_sys_save)); | ||
314 | |||
315 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
316 | |||
317 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
318 | scu_enable(S5P_VA_SCU); | ||
319 | |||
320 | early_wakeup: | ||
321 | |||
322 | /* Clear SLEEP mode set in INFORM1 */ | ||
323 | pmu_raw_writel(0x0, S5P_INFORM1); | ||
324 | |||
325 | return; | ||
326 | } | ||
327 | |||
328 | static struct syscore_ops exynos_pm_syscore_ops = { | ||
329 | .suspend = exynos_pm_suspend, | ||
330 | .resume = exynos_pm_resume, | ||
331 | }; | ||
332 | |||
333 | /* | ||
334 | * Suspend Ops | ||
335 | */ | ||
336 | |||
337 | static int exynos_suspend_enter(suspend_state_t state) | ||
338 | { | ||
339 | int ret; | ||
340 | |||
341 | s3c_pm_debug_init(); | ||
342 | |||
343 | S3C_PMDBG("%s: suspending the system...\n", __func__); | ||
344 | |||
345 | S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, | ||
346 | exynos_irqwake_intmask, exynos_get_eint_wake_mask()); | ||
347 | |||
348 | if (exynos_irqwake_intmask == -1U | ||
349 | && exynos_get_eint_wake_mask() == -1U) { | ||
350 | pr_err("%s: No wake-up sources!\n", __func__); | ||
351 | pr_err("%s: Aborting sleep\n", __func__); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | s3c_pm_save_uarts(); | ||
356 | exynos_pm_prepare(); | ||
357 | flush_cache_all(); | ||
358 | s3c_pm_check_store(); | ||
359 | |||
360 | ret = cpu_suspend(0, exynos_cpu_suspend); | ||
361 | if (ret) | ||
362 | return ret; | ||
363 | |||
364 | s3c_pm_restore_uarts(); | ||
365 | |||
366 | S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, | ||
367 | pmu_raw_readl(S5P_WAKEUP_STAT)); | ||
368 | |||
369 | s3c_pm_check_restore(); | ||
370 | |||
371 | S3C_PMDBG("%s: resuming the system...\n", __func__); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int exynos_suspend_prepare(void) | ||
377 | { | ||
378 | s3c_pm_check_prepare(); | ||
379 | |||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static void exynos_suspend_finish(void) | ||
384 | { | ||
385 | s3c_pm_check_cleanup(); | ||
386 | } | ||
387 | |||
388 | static const struct platform_suspend_ops exynos_suspend_ops = { | ||
389 | .enter = exynos_suspend_enter, | ||
390 | .prepare = exynos_suspend_prepare, | ||
391 | .finish = exynos_suspend_finish, | ||
392 | .valid = suspend_valid_only_mem, | ||
393 | }; | ||
394 | |||
395 | void __init exynos_pm_init(void) | ||
396 | { | ||
397 | u32 tmp; | ||
398 | |||
399 | /* Platform-specific GIC callback */ | ||
400 | gic_arch_extn.irq_set_wake = exynos_irq_set_wake; | ||
401 | |||
402 | /* All wakeup disable */ | ||
403 | tmp = pmu_raw_readl(S5P_WAKEUP_MASK); | ||
404 | tmp |= ((0xFF << 8) | (0x1F << 1)); | ||
405 | pmu_raw_writel(tmp, S5P_WAKEUP_MASK); | ||
406 | |||
407 | register_syscore_ops(&exynos_pm_syscore_ops); | ||
408 | suspend_set_ops(&exynos_suspend_ops); | ||
409 | } | ||
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c index d8fa0337db73..c15761ca2f18 100644 --- a/arch/arm/mach-exynos/pmu.c +++ b/arch/arm/mach-exynos/pmu.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd. | 2 | * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. |
3 | * http://www.samsung.com/ | 3 | * http://www.samsung.com/ |
4 | * | 4 | * |
5 | * EXYNOS - CPU PMU(Power Management Unit) support | 5 | * EXYNOS - CPU PMU(Power Management Unit) support |
@@ -10,12 +10,136 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/io.h> | 12 | #include <linux/io.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/of.h> |
14 | #include <linux/of_address.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/notifier.h> | ||
18 | #include <linux/reboot.h> | ||
14 | 19 | ||
15 | #include "common.h" | 20 | |
21 | #include "exynos-pmu.h" | ||
16 | #include "regs-pmu.h" | 22 | #include "regs-pmu.h" |
17 | 23 | ||
18 | static const struct exynos_pmu_conf *exynos_pmu_config; | 24 | #define PMU_TABLE_END (-1U) |
25 | |||
26 | struct exynos_pmu_conf { | ||
27 | unsigned int offset; | ||
28 | u8 val[NUM_SYS_POWERDOWN]; | ||
29 | }; | ||
30 | |||
31 | struct exynos_pmu_data { | ||
32 | const struct exynos_pmu_conf *pmu_config; | ||
33 | const struct exynos_pmu_conf *pmu_config_extra; | ||
34 | |||
35 | void (*pmu_init)(void); | ||
36 | void (*powerdown_conf)(enum sys_powerdown); | ||
37 | void (*powerdown_conf_extra)(enum sys_powerdown); | ||
38 | }; | ||
39 | |||
40 | struct exynos_pmu_context { | ||
41 | struct device *dev; | ||
42 | const struct exynos_pmu_data *pmu_data; | ||
43 | }; | ||
44 | |||
45 | static void __iomem *pmu_base_addr; | ||
46 | static struct exynos_pmu_context *pmu_context; | ||
47 | |||
48 | static inline void pmu_raw_writel(u32 val, u32 offset) | ||
49 | { | ||
50 | writel_relaxed(val, pmu_base_addr + offset); | ||
51 | } | ||
52 | |||
53 | static inline u32 pmu_raw_readl(u32 offset) | ||
54 | { | ||
55 | return readl_relaxed(pmu_base_addr + offset); | ||
56 | } | ||
57 | |||
58 | static struct exynos_pmu_conf exynos3250_pmu_config[] = { | ||
59 | /* { .offset = offset, .val = { AFTR, W-AFTR, SLEEP } */ | ||
60 | { EXYNOS3_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, | ||
61 | { EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
62 | { EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
63 | { EXYNOS3_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, | ||
64 | { EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
65 | { EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
66 | { EXYNOS3_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
67 | { EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
68 | { EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
69 | { EXYNOS3_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x2} }, | ||
70 | { EXYNOS3_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x3} }, | ||
71 | { EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
72 | { EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
73 | { EXYNOS3_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
74 | { EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
75 | { EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
76 | { EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
77 | { EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
78 | { EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
79 | { EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
80 | { EXYNOS3_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
81 | { EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
82 | { EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
83 | { EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
84 | { EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
85 | { EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
86 | { EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
87 | { EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
88 | { EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
89 | { EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
90 | { EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
91 | { EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
92 | { EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
93 | { EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
94 | { EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
95 | { EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
96 | { EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
97 | { EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
98 | { EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
99 | { EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
100 | { EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
101 | { EXYNOS3_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | ||
102 | { EXYNOS3_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
103 | { EXYNOS3_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x3} }, | ||
104 | { EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | ||
105 | { EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
106 | { EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG, { 0x3, 0x3, 0x3} }, | ||
107 | { EXYNOS3_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
108 | { EXYNOS3_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
109 | { EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
110 | { EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, | ||
111 | { EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
112 | { EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
113 | { EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
114 | { EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
115 | { EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
116 | { EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
117 | { EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
118 | { EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
119 | { EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
120 | { EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
121 | { EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
122 | { EXYNOS3_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
123 | { EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
124 | { EXYNOS3_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
125 | { EXYNOS3_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
126 | { EXYNOS3_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
127 | { EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
128 | { EXYNOS3_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
129 | { EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
130 | { EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
131 | { EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
132 | { EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
133 | { EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
134 | { EXYNOS3_CAM_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
135 | { EXYNOS3_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
136 | { EXYNOS3_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
137 | { EXYNOS3_LCD0_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
138 | { EXYNOS3_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
139 | { EXYNOS3_MAUDIO_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
140 | { EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
141 | { PMU_TABLE_END,}, | ||
142 | }; | ||
19 | 143 | ||
20 | static const struct exynos_pmu_conf exynos4210_pmu_config[] = { | 144 | static const struct exynos_pmu_conf exynos4210_pmu_config[] = { |
21 | /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ | 145 | /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ |
@@ -264,6 +388,7 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { | |||
264 | { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | 388 | { EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, |
265 | { EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | 389 | { EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, |
266 | { EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | 390 | { EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, |
391 | { EXYNOS5_JPEG_MEM_OPTION, { 0x10, 0x10, 0x0} }, | ||
267 | { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | 392 | { EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, |
268 | { EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | 393 | { EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, |
269 | { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | 394 | { EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, |
@@ -315,6 +440,189 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = { | |||
315 | { PMU_TABLE_END,}, | 440 | { PMU_TABLE_END,}, |
316 | }; | 441 | }; |
317 | 442 | ||
443 | static struct exynos_pmu_conf exynos5420_pmu_config[] = { | ||
444 | /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */ | ||
445 | { EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
446 | { EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
447 | { EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
448 | { EXYNOS5_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
449 | { EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
450 | { EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
451 | { EXYNOS5420_ARM_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
452 | { EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
453 | { EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
454 | { EXYNOS5420_ARM_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
455 | { EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
456 | { EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
457 | { EXYNOS5420_KFC_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
458 | { EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
459 | { EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
460 | { EXYNOS5420_KFC_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
461 | { EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
462 | { EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
463 | { EXYNOS5420_KFC_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
464 | { EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
465 | { EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
466 | { EXYNOS5420_KFC_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
467 | { EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
468 | { EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
469 | { EXYNOS5_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
470 | { EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
471 | { EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
472 | { EXYNOS5420_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
473 | { EXYNOS5420_KFC_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
474 | { EXYNOS5_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
475 | { EXYNOS5420_KFC_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
476 | { EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
477 | { EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, | ||
478 | { EXYNOS5_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
479 | { EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
480 | { EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, | ||
481 | { EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
482 | { EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, | ||
483 | { EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
484 | { EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, | ||
485 | { EXYNOS5_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
486 | { EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
487 | { EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
488 | { EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
489 | { EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
490 | { EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
491 | { EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
492 | { EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
493 | { EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
494 | { EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
495 | { EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
496 | { EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
497 | { EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
498 | { EXYNOS5_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | ||
499 | { EXYNOS5_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} }, | ||
500 | { EXYNOS5_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x0} }, | ||
501 | { EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | ||
502 | { EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, | ||
503 | { EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} }, | ||
504 | { EXYNOS5_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
505 | { EXYNOS5_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x0, 0x1} }, | ||
506 | { EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
507 | { EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
508 | { EXYNOS5420_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, | ||
509 | { EXYNOS5420_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} }, | ||
510 | { EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
511 | { EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
512 | { EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
513 | { EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
514 | { EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
515 | { EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
516 | { EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
517 | { EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
518 | { EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
519 | { EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
520 | { EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
521 | { EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
522 | { EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
523 | { EXYNOS5_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
524 | { EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
525 | { EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
526 | { EXYNOS5_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
527 | { EXYNOS5_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
528 | { EXYNOS5_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
529 | { EXYNOS5_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
530 | { EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
531 | { EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
532 | { EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} }, | ||
533 | { EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x0} }, | ||
534 | { EXYNOS5_GSCL_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
535 | { EXYNOS5_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
536 | { EXYNOS5_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
537 | { EXYNOS5_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
538 | { EXYNOS5420_DISP1_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
539 | { EXYNOS5420_MAU_SYS_PWR_REG, { 0x7, 0x7, 0x0} }, | ||
540 | { EXYNOS5420_G2D_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
541 | { EXYNOS5420_MSC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
542 | { EXYNOS5420_FSYS_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
543 | { EXYNOS5420_FSYS2_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
544 | { EXYNOS5420_PSGEN_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
545 | { EXYNOS5420_PERIC_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
546 | { EXYNOS5420_WCORE_SYS_PWR_REG, { 0x7, 0x0, 0x0} }, | ||
547 | { EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
548 | { EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
549 | { EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
550 | { EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
551 | { EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
552 | { EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
553 | { EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
554 | { EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
555 | { EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
556 | { EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
557 | { EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
558 | { EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
559 | { EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
560 | { EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
561 | { EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
562 | { EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
563 | { EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
564 | { EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
565 | { EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
566 | { EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
567 | { EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
568 | { EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
569 | { EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
570 | { EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
571 | { EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
572 | { EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
573 | { EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
574 | { EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
575 | { EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
576 | { EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
577 | { EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
578 | { EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
579 | { EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
580 | { EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
581 | { EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
582 | { EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
583 | { EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
584 | { EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} }, | ||
585 | { PMU_TABLE_END,}, | ||
586 | }; | ||
587 | |||
588 | static unsigned int const exynos3250_list_feed[] = { | ||
589 | EXYNOS3_ARM_CORE_OPTION(0), | ||
590 | EXYNOS3_ARM_CORE_OPTION(1), | ||
591 | EXYNOS3_ARM_CORE_OPTION(2), | ||
592 | EXYNOS3_ARM_CORE_OPTION(3), | ||
593 | EXYNOS3_ARM_COMMON_OPTION, | ||
594 | EXYNOS3_TOP_PWR_OPTION, | ||
595 | EXYNOS3_CORE_TOP_PWR_OPTION, | ||
596 | S5P_CAM_OPTION, | ||
597 | S5P_MFC_OPTION, | ||
598 | S5P_G3D_OPTION, | ||
599 | S5P_LCD0_OPTION, | ||
600 | S5P_ISP_OPTION, | ||
601 | }; | ||
602 | |||
603 | static void exynos3250_powerdown_conf_extra(enum sys_powerdown mode) | ||
604 | { | ||
605 | unsigned int i; | ||
606 | unsigned int tmp; | ||
607 | |||
608 | /* Enable only SC_FEEDBACK */ | ||
609 | for (i = 0; i < ARRAY_SIZE(exynos3250_list_feed); i++) { | ||
610 | tmp = pmu_raw_readl(exynos3250_list_feed[i]); | ||
611 | tmp &= ~(EXYNOS3_OPTION_USE_SC_COUNTER); | ||
612 | tmp |= EXYNOS3_OPTION_USE_SC_FEEDBACK; | ||
613 | pmu_raw_writel(tmp, exynos3250_list_feed[i]); | ||
614 | } | ||
615 | |||
616 | if (mode != SYS_SLEEP) | ||
617 | return; | ||
618 | |||
619 | pmu_raw_writel(XUSBXTI_DURATION, EXYNOS3_XUSBXTI_DURATION); | ||
620 | pmu_raw_writel(XXTI_DURATION, EXYNOS3_XXTI_DURATION); | ||
621 | pmu_raw_writel(EXT_REGULATOR_DURATION, EXYNOS3_EXT_REGULATOR_DURATION); | ||
622 | pmu_raw_writel(EXT_REGULATOR_COREBLK_DURATION, | ||
623 | EXYNOS3_EXT_REGULATOR_COREBLK_DURATION); | ||
624 | } | ||
625 | |||
318 | static unsigned int const exynos5_list_both_cnt_feed[] = { | 626 | static unsigned int const exynos5_list_both_cnt_feed[] = { |
319 | EXYNOS5_ARM_CORE0_OPTION, | 627 | EXYNOS5_ARM_CORE0_OPTION, |
320 | EXYNOS5_ARM_CORE1_OPTION, | 628 | EXYNOS5_ARM_CORE1_OPTION, |
@@ -335,7 +643,76 @@ static unsigned int const exynos5_list_disable_wfi_wfe[] = { | |||
335 | EXYNOS5_ISP_ARM_OPTION, | 643 | EXYNOS5_ISP_ARM_OPTION, |
336 | }; | 644 | }; |
337 | 645 | ||
338 | static void exynos5_init_pmu(void) | 646 | static unsigned int const exynos5420_list_disable_pmu_reg[] = { |
647 | EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, | ||
648 | EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, | ||
649 | EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, | ||
650 | EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, | ||
651 | EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, | ||
652 | EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, | ||
653 | EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, | ||
654 | EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, | ||
655 | EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, | ||
656 | EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, | ||
657 | EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, | ||
658 | EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, | ||
659 | EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, | ||
660 | EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, | ||
661 | EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, | ||
662 | EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, | ||
663 | EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, | ||
664 | EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, | ||
665 | EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, | ||
666 | EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, | ||
667 | EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, | ||
668 | EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, | ||
669 | EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, | ||
670 | EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, | ||
671 | EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, | ||
672 | EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, | ||
673 | EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, | ||
674 | EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, | ||
675 | EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, | ||
676 | EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, | ||
677 | EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, | ||
678 | EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, | ||
679 | EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, | ||
680 | EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, | ||
681 | EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, | ||
682 | }; | ||
683 | |||
684 | static void exynos5_power_off(void) | ||
685 | { | ||
686 | unsigned int tmp; | ||
687 | |||
688 | pr_info("Power down.\n"); | ||
689 | tmp = pmu_raw_readl(EXYNOS_PS_HOLD_CONTROL); | ||
690 | tmp ^= (1 << 8); | ||
691 | pmu_raw_writel(tmp, EXYNOS_PS_HOLD_CONTROL); | ||
692 | |||
693 | /* Wait a little so we don't give a false warning below */ | ||
694 | mdelay(100); | ||
695 | |||
696 | pr_err("Power down failed, please power off system manually.\n"); | ||
697 | while (1) | ||
698 | ; | ||
699 | } | ||
700 | |||
701 | void exynos5420_powerdown_conf(enum sys_powerdown mode) | ||
702 | { | ||
703 | u32 this_cluster; | ||
704 | |||
705 | this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); | ||
706 | |||
707 | /* | ||
708 | * set the cluster id to IROM register to ensure that we wake | ||
709 | * up with the current cluster. | ||
710 | */ | ||
711 | pmu_raw_writel(this_cluster, EXYNOS_IROM_DATA2); | ||
712 | } | ||
713 | |||
714 | |||
715 | static void exynos5_powerdown_conf(enum sys_powerdown mode) | ||
339 | { | 716 | { |
340 | unsigned int i; | 717 | unsigned int i; |
341 | unsigned int tmp; | 718 | unsigned int tmp; |
@@ -343,7 +720,7 @@ static void exynos5_init_pmu(void) | |||
343 | /* | 720 | /* |
344 | * Enable both SC_FEEDBACK and SC_COUNTER | 721 | * Enable both SC_FEEDBACK and SC_COUNTER |
345 | */ | 722 | */ |
346 | for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) { | 723 | for (i = 0; i < ARRAY_SIZE(exynos5_list_both_cnt_feed); i++) { |
347 | tmp = pmu_raw_readl(exynos5_list_both_cnt_feed[i]); | 724 | tmp = pmu_raw_readl(exynos5_list_both_cnt_feed[i]); |
348 | tmp |= (EXYNOS5_USE_SC_FEEDBACK | | 725 | tmp |= (EXYNOS5_USE_SC_FEEDBACK | |
349 | EXYNOS5_USE_SC_COUNTER); | 726 | EXYNOS5_USE_SC_COUNTER); |
@@ -360,7 +737,7 @@ static void exynos5_init_pmu(void) | |||
360 | /* | 737 | /* |
361 | * Disable WFI/WFE on XXX_OPTION | 738 | * Disable WFI/WFE on XXX_OPTION |
362 | */ | 739 | */ |
363 | for (i = 0 ; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe) ; i++) { | 740 | for (i = 0; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe); i++) { |
364 | tmp = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]); | 741 | tmp = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]); |
365 | tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | | 742 | tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE | |
366 | EXYNOS5_OPTION_USE_STANDBYWFI); | 743 | EXYNOS5_OPTION_USE_STANDBYWFI); |
@@ -372,51 +749,257 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode) | |||
372 | { | 749 | { |
373 | unsigned int i; | 750 | unsigned int i; |
374 | 751 | ||
375 | if (soc_is_exynos5250()) | 752 | const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data; |
376 | exynos5_init_pmu(); | 753 | |
754 | if (pmu_data->powerdown_conf) | ||
755 | pmu_data->powerdown_conf(mode); | ||
756 | |||
757 | if (pmu_data->pmu_config) { | ||
758 | for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++) | ||
759 | pmu_raw_writel(pmu_data->pmu_config[i].val[mode], | ||
760 | pmu_data->pmu_config[i].offset); | ||
761 | } | ||
377 | 762 | ||
378 | for (i = 0; (exynos_pmu_config[i].offset != PMU_TABLE_END) ; i++) | 763 | if (pmu_data->powerdown_conf_extra) |
379 | pmu_raw_writel(exynos_pmu_config[i].val[mode], | 764 | pmu_data->powerdown_conf_extra(mode); |
380 | exynos_pmu_config[i].offset); | ||
381 | 765 | ||
382 | if (soc_is_exynos4412()) { | 766 | if (pmu_data->pmu_config_extra) { |
383 | for (i = 0; exynos4412_pmu_config[i].offset != PMU_TABLE_END ; i++) | 767 | for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++) |
384 | pmu_raw_writel(exynos4412_pmu_config[i].val[mode], | 768 | pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode], |
385 | exynos4412_pmu_config[i].offset); | 769 | pmu_data->pmu_config_extra[i].offset); |
386 | } | 770 | } |
387 | } | 771 | } |
388 | 772 | ||
389 | static int __init exynos_pmu_init(void) | 773 | static void exynos3250_pmu_init(void) |
774 | { | ||
775 | unsigned int value; | ||
776 | |||
777 | /* | ||
778 | * To prevent from issuing new bus request form L2 memory system | ||
779 | * If core status is power down, should be set '1' to L2 power down | ||
780 | */ | ||
781 | value = pmu_raw_readl(EXYNOS3_ARM_COMMON_OPTION); | ||
782 | value |= EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN; | ||
783 | pmu_raw_writel(value, EXYNOS3_ARM_COMMON_OPTION); | ||
784 | |||
785 | /* Enable USE_STANDBY_WFI for all CORE */ | ||
786 | pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); | ||
787 | |||
788 | /* | ||
789 | * Set PSHOLD port for output high | ||
790 | */ | ||
791 | value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); | ||
792 | value |= S5P_PS_HOLD_OUTPUT_HIGH; | ||
793 | pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); | ||
794 | |||
795 | /* | ||
796 | * Enable signal for PSHOLD port | ||
797 | */ | ||
798 | value = pmu_raw_readl(S5P_PS_HOLD_CONTROL); | ||
799 | value |= S5P_PS_HOLD_EN; | ||
800 | pmu_raw_writel(value, S5P_PS_HOLD_CONTROL); | ||
801 | } | ||
802 | |||
803 | static void exynos5250_pmu_init(void) | ||
390 | { | 804 | { |
391 | unsigned int value; | 805 | unsigned int value; |
806 | /* | ||
807 | * When SYS_WDTRESET is set, watchdog timer reset request | ||
808 | * is ignored by power management unit. | ||
809 | */ | ||
810 | value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); | ||
811 | value &= ~EXYNOS5_SYS_WDTRESET; | ||
812 | pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); | ||
813 | |||
814 | value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); | ||
815 | value &= ~EXYNOS5_SYS_WDTRESET; | ||
816 | pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); | ||
817 | } | ||
818 | |||
819 | static void exynos5420_pmu_init(void) | ||
820 | { | ||
821 | unsigned int value; | ||
822 | int i; | ||
823 | |||
824 | /* | ||
825 | * Set the CMU_RESET, CMU_SYSCLK and CMU_CLKSTOP registers | ||
826 | * for local power blocks to Low initially as per Table 8-4: | ||
827 | * "System-Level Power-Down Configuration Registers". | ||
828 | */ | ||
829 | for (i = 0; i < ARRAY_SIZE(exynos5420_list_disable_pmu_reg); i++) | ||
830 | pmu_raw_writel(0, exynos5420_list_disable_pmu_reg[i]); | ||
831 | |||
832 | /* Enable USE_STANDBY_WFI for all CORE */ | ||
833 | pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION); | ||
834 | |||
835 | value = pmu_raw_readl(EXYNOS_L2_OPTION(0)); | ||
836 | value &= ~EXYNOS5_USE_RETENTION; | ||
837 | pmu_raw_writel(value, EXYNOS_L2_OPTION(0)); | ||
838 | |||
839 | value = pmu_raw_readl(EXYNOS_L2_OPTION(1)); | ||
840 | value &= ~EXYNOS5_USE_RETENTION; | ||
841 | pmu_raw_writel(value, EXYNOS_L2_OPTION(1)); | ||
842 | |||
843 | /* | ||
844 | * If L2_COMMON is turned off, clocks related to ATB async | ||
845 | * bridge are gated. Thus, when ISP power is gated, LPI | ||
846 | * may get stuck. | ||
847 | */ | ||
848 | value = pmu_raw_readl(EXYNOS5420_LPI_MASK); | ||
849 | value |= EXYNOS5420_ATB_ISP_ARM; | ||
850 | pmu_raw_writel(value, EXYNOS5420_LPI_MASK); | ||
851 | |||
852 | value = pmu_raw_readl(EXYNOS5420_LPI_MASK1); | ||
853 | value |= EXYNOS5420_ATB_KFC; | ||
854 | pmu_raw_writel(value, EXYNOS5420_LPI_MASK1); | ||
855 | |||
856 | /* Prevent issue of new bus request from L2 memory */ | ||
857 | value = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); | ||
858 | value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; | ||
859 | pmu_raw_writel(value, EXYNOS5420_ARM_COMMON_OPTION); | ||
860 | |||
861 | value = pmu_raw_readl(EXYNOS5420_KFC_COMMON_OPTION); | ||
862 | value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN; | ||
863 | pmu_raw_writel(value, EXYNOS5420_KFC_COMMON_OPTION); | ||
864 | |||
865 | /* This setting is to reduce suspend/resume time */ | ||
866 | pmu_raw_writel(DUR_WAIT_RESET, EXYNOS5420_LOGIC_RESET_DURATION3); | ||
867 | |||
868 | /* Serialized CPU wakeup of Eagle */ | ||
869 | pmu_raw_writel(SPREAD_ENABLE, EXYNOS5420_ARM_INTR_SPREAD_ENABLE); | ||
870 | |||
871 | pmu_raw_writel(SPREAD_USE_STANDWFI, | ||
872 | EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI); | ||
873 | |||
874 | pmu_raw_writel(0x1, EXYNOS5420_UP_SCHEDULER); | ||
875 | |||
876 | pm_power_off = exynos5_power_off; | ||
877 | pr_info("EXYNOS5420 PMU initialized\n"); | ||
878 | } | ||
879 | |||
880 | static int pmu_restart_notify(struct notifier_block *this, | ||
881 | unsigned long code, void *unused) | ||
882 | { | ||
883 | pmu_raw_writel(0x1, EXYNOS_SWRESET); | ||
884 | |||
885 | return NOTIFY_DONE; | ||
886 | } | ||
887 | |||
888 | static const struct exynos_pmu_data exynos3250_pmu_data = { | ||
889 | .pmu_config = exynos3250_pmu_config, | ||
890 | .pmu_init = exynos3250_pmu_init, | ||
891 | .powerdown_conf_extra = exynos3250_powerdown_conf_extra, | ||
892 | }; | ||
392 | 893 | ||
393 | exynos_pmu_config = exynos4210_pmu_config; | 894 | static const struct exynos_pmu_data exynos4210_pmu_data = { |
394 | 895 | .pmu_config = exynos4210_pmu_config, | |
395 | if (soc_is_exynos4210()) { | 896 | }; |
396 | exynos_pmu_config = exynos4210_pmu_config; | 897 | |
397 | pr_info("EXYNOS4210 PMU Initialize\n"); | 898 | static const struct exynos_pmu_data exynos4212_pmu_data = { |
398 | } else if (soc_is_exynos4212() || soc_is_exynos4412()) { | 899 | .pmu_config = exynos4x12_pmu_config, |
399 | exynos_pmu_config = exynos4x12_pmu_config; | 900 | }; |
400 | pr_info("EXYNOS4x12 PMU Initialize\n"); | 901 | |
401 | } else if (soc_is_exynos5250()) { | 902 | static const struct exynos_pmu_data exynos4412_pmu_data = { |
402 | /* | 903 | .pmu_config = exynos4x12_pmu_config, |
403 | * When SYS_WDTRESET is set, watchdog timer reset request | 904 | .pmu_config_extra = exynos4412_pmu_config, |
404 | * is ignored by power management unit. | 905 | }; |
405 | */ | 906 | |
406 | value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE); | 907 | static const struct exynos_pmu_data exynos5250_pmu_data = { |
407 | value &= ~EXYNOS5_SYS_WDTRESET; | 908 | .pmu_config = exynos5250_pmu_config, |
408 | pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE); | 909 | .pmu_init = exynos5250_pmu_init, |
409 | 910 | .powerdown_conf = exynos5_powerdown_conf, | |
410 | value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST); | 911 | }; |
411 | value &= ~EXYNOS5_SYS_WDTRESET; | 912 | |
412 | pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST); | 913 | static struct exynos_pmu_data exynos5420_pmu_data = { |
413 | 914 | .pmu_config = exynos5420_pmu_config, | |
414 | exynos_pmu_config = exynos5250_pmu_config; | 915 | .pmu_init = exynos5420_pmu_init, |
415 | pr_info("EXYNOS5250 PMU Initialize\n"); | 916 | .powerdown_conf = exynos5420_powerdown_conf, |
416 | } else { | 917 | }; |
417 | pr_info("EXYNOS: PMU not supported\n"); | 918 | |
919 | /* | ||
920 | * PMU platform driver and devicetree bindings. | ||
921 | */ | ||
922 | static const struct of_device_id exynos_pmu_of_device_ids[] = { | ||
923 | { | ||
924 | .compatible = "samsung,exynos3250-pmu", | ||
925 | .data = &exynos3250_pmu_data, | ||
926 | }, { | ||
927 | .compatible = "samsung,exynos4210-pmu", | ||
928 | .data = &exynos4210_pmu_data, | ||
929 | }, { | ||
930 | .compatible = "samsung,exynos4212-pmu", | ||
931 | .data = &exynos4212_pmu_data, | ||
932 | }, { | ||
933 | .compatible = "samsung,exynos4412-pmu", | ||
934 | .data = &exynos4412_pmu_data, | ||
935 | }, { | ||
936 | .compatible = "samsung,exynos5250-pmu", | ||
937 | .data = &exynos5250_pmu_data, | ||
938 | }, { | ||
939 | .compatible = "samsung,exynos5420-pmu", | ||
940 | .data = &exynos5420_pmu_data, | ||
941 | }, | ||
942 | { /*sentinel*/ }, | ||
943 | }; | ||
944 | |||
945 | /* | ||
946 | * Exynos PMU restart notifier, handles restart functionality | ||
947 | */ | ||
948 | static struct notifier_block pmu_restart_handler = { | ||
949 | .notifier_call = pmu_restart_notify, | ||
950 | .priority = 128, | ||
951 | }; | ||
952 | |||
953 | static int exynos_pmu_probe(struct platform_device *pdev) | ||
954 | { | ||
955 | const struct of_device_id *match; | ||
956 | struct device *dev = &pdev->dev; | ||
957 | struct resource *res; | ||
958 | int ret; | ||
959 | |||
960 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
961 | pmu_base_addr = devm_ioremap_resource(dev, res); | ||
962 | if (IS_ERR(pmu_base_addr)) | ||
963 | return PTR_ERR(pmu_base_addr); | ||
964 | |||
965 | pmu_context = devm_kzalloc(&pdev->dev, | ||
966 | sizeof(struct exynos_pmu_context), | ||
967 | GFP_KERNEL); | ||
968 | if (!pmu_context) { | ||
969 | dev_err(dev, "Cannot allocate memory.\n"); | ||
970 | return -ENOMEM; | ||
418 | } | 971 | } |
972 | pmu_context->dev = dev; | ||
973 | |||
974 | match = of_match_node(exynos_pmu_of_device_ids, dev->of_node); | ||
975 | |||
976 | pmu_context->pmu_data = match->data; | ||
977 | |||
978 | if (pmu_context->pmu_data->pmu_init) | ||
979 | pmu_context->pmu_data->pmu_init(); | ||
980 | |||
981 | platform_set_drvdata(pdev, pmu_context); | ||
419 | 982 | ||
983 | ret = register_restart_handler(&pmu_restart_handler); | ||
984 | if (ret) | ||
985 | dev_warn(dev, "can't register restart handler err=%d\n", ret); | ||
986 | |||
987 | dev_dbg(dev, "Exynos PMU Driver probe done\n"); | ||
420 | return 0; | 988 | return 0; |
421 | } | 989 | } |
422 | arch_initcall(exynos_pmu_init); | 990 | |
991 | static struct platform_driver exynos_pmu_driver = { | ||
992 | .driver = { | ||
993 | .name = "exynos-pmu", | ||
994 | .owner = THIS_MODULE, | ||
995 | .of_match_table = exynos_pmu_of_device_ids, | ||
996 | }, | ||
997 | .probe = exynos_pmu_probe, | ||
998 | }; | ||
999 | |||
1000 | static int __init exynos_pmu_init(void) | ||
1001 | { | ||
1002 | return platform_driver_register(&exynos_pmu_driver); | ||
1003 | |||
1004 | } | ||
1005 | postcore_initcall(exynos_pmu_init); | ||
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h index 4e9b4440e2bd..b5f4406fc1b5 100644 --- a/arch/arm/mach-exynos/regs-pmu.h +++ b/arch/arm/mach-exynos/regs-pmu.h | |||
@@ -19,9 +19,24 @@ | |||
19 | #define S5P_CENTRAL_SEQ_OPTION 0x0208 | 19 | #define S5P_CENTRAL_SEQ_OPTION 0x0208 |
20 | 20 | ||
21 | #define S5P_USE_STANDBY_WFI0 (1 << 16) | 21 | #define S5P_USE_STANDBY_WFI0 (1 << 16) |
22 | #define S5P_USE_STANDBY_WFI1 (1 << 17) | ||
23 | #define S5P_USE_STANDBY_WFI2 (1 << 19) | ||
24 | #define S5P_USE_STANDBY_WFI3 (1 << 20) | ||
22 | #define S5P_USE_STANDBY_WFE0 (1 << 24) | 25 | #define S5P_USE_STANDBY_WFE0 (1 << 24) |
26 | #define S5P_USE_STANDBY_WFE1 (1 << 25) | ||
27 | #define S5P_USE_STANDBY_WFE2 (1 << 27) | ||
28 | #define S5P_USE_STANDBY_WFE3 (1 << 28) | ||
29 | |||
30 | #define S5P_USE_STANDBY_WFI_ALL \ | ||
31 | (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFI1 | \ | ||
32 | S5P_USE_STANDBY_WFI2 | S5P_USE_STANDBY_WFI3 | \ | ||
33 | S5P_USE_STANDBY_WFE0 | S5P_USE_STANDBY_WFE1 | \ | ||
34 | S5P_USE_STANDBY_WFE2 | S5P_USE_STANDBY_WFE3) | ||
35 | |||
23 | #define S5P_USE_DELAYED_RESET_ASSERTION BIT(12) | 36 | #define S5P_USE_DELAYED_RESET_ASSERTION BIT(12) |
24 | 37 | ||
38 | #define EXYNOS_CORE_PO_RESET(n) ((1 << 4) << n) | ||
39 | #define EXYNOS_WAKEUP_FROM_LOWPWR (1 << 28) | ||
25 | #define EXYNOS_SWRESET 0x0400 | 40 | #define EXYNOS_SWRESET 0x0400 |
26 | #define EXYNOS5440_SWRESET 0x00C4 | 41 | #define EXYNOS5440_SWRESET 0x00C4 |
27 | 42 | ||
@@ -36,6 +51,7 @@ | |||
36 | #define S5P_INFORM7 0x081C | 51 | #define S5P_INFORM7 0x081C |
37 | #define S5P_PMU_SPARE3 0x090C | 52 | #define S5P_PMU_SPARE3 0x090C |
38 | 53 | ||
54 | #define EXYNOS_IROM_DATA2 0x0988 | ||
39 | #define S5P_ARM_CORE0_LOWPWR 0x1000 | 55 | #define S5P_ARM_CORE0_LOWPWR 0x1000 |
40 | #define S5P_DIS_IRQ_CORE0 0x1004 | 56 | #define S5P_DIS_IRQ_CORE0 0x1004 |
41 | #define S5P_DIS_IRQ_CENTRAL0 0x1008 | 57 | #define S5P_DIS_IRQ_CENTRAL0 0x1008 |
@@ -118,6 +134,31 @@ | |||
118 | #define EXYNOS_COMMON_OPTION(_nr) \ | 134 | #define EXYNOS_COMMON_OPTION(_nr) \ |
119 | (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) | 135 | (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) |
120 | 136 | ||
137 | #define EXYNOS_CORE_LOCAL_PWR_EN 0x3 | ||
138 | |||
139 | #define EXYNOS_ARM_COMMON_STATUS 0x2504 | ||
140 | #define EXYNOS_COMMON_OPTION(_nr) \ | ||
141 | (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8) | ||
142 | |||
143 | #define EXYNOS_ARM_L2_CONFIGURATION 0x2600 | ||
144 | #define EXYNOS_L2_CONFIGURATION(_nr) \ | ||
145 | (EXYNOS_ARM_L2_CONFIGURATION + ((_nr) * 0x80)) | ||
146 | #define EXYNOS_L2_STATUS(_nr) \ | ||
147 | (EXYNOS_L2_CONFIGURATION(_nr) + 0x4) | ||
148 | #define EXYNOS_L2_OPTION(_nr) \ | ||
149 | (EXYNOS_L2_CONFIGURATION(_nr) + 0x8) | ||
150 | #define EXYNOS_L2_COMMON_PWR_EN 0x3 | ||
151 | |||
152 | #define EXYNOS_ARM_CORE_X_STATUS_OFFSET 0x4 | ||
153 | |||
154 | #define EXYNOS5_APLL_SYSCLK_CONFIGURATION 0x2A00 | ||
155 | #define EXYNOS5_APLL_SYSCLK_STATUS 0x2A04 | ||
156 | |||
157 | #define EXYNOS5_ARM_L2_OPTION 0x2608 | ||
158 | #define EXYNOS5_USE_RETENTION BIT(4) | ||
159 | |||
160 | #define EXYNOS5_L2RSTDISABLE_VALUE BIT(3) | ||
161 | |||
121 | #define S5P_PAD_RET_MAUDIO_OPTION 0x3028 | 162 | #define S5P_PAD_RET_MAUDIO_OPTION 0x3028 |
122 | #define S5P_PAD_RET_GPIO_OPTION 0x3108 | 163 | #define S5P_PAD_RET_GPIO_OPTION 0x3108 |
123 | #define S5P_PAD_RET_UART_OPTION 0x3128 | 164 | #define S5P_PAD_RET_UART_OPTION 0x3128 |
@@ -126,7 +167,19 @@ | |||
126 | #define S5P_PAD_RET_EBIA_OPTION 0x3188 | 167 | #define S5P_PAD_RET_EBIA_OPTION 0x3188 |
127 | #define S5P_PAD_RET_EBIB_OPTION 0x31A8 | 168 | #define S5P_PAD_RET_EBIB_OPTION 0x31A8 |
128 | 169 | ||
170 | #define S5P_PS_HOLD_CONTROL 0x330C | ||
171 | #define S5P_PS_HOLD_EN (1 << 31) | ||
172 | #define S5P_PS_HOLD_OUTPUT_HIGH (3 << 8) | ||
173 | |||
174 | #define S5P_CAM_OPTION 0x3C08 | ||
175 | #define S5P_MFC_OPTION 0x3C48 | ||
176 | #define S5P_G3D_OPTION 0x3C68 | ||
177 | #define S5P_LCD0_OPTION 0x3C88 | ||
178 | #define S5P_LCD1_OPTION 0x3CA8 | ||
179 | #define S5P_ISP_OPTION S5P_LCD1_OPTION | ||
180 | |||
129 | #define S5P_CORE_LOCAL_PWR_EN 0x3 | 181 | #define S5P_CORE_LOCAL_PWR_EN 0x3 |
182 | #define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8) | ||
130 | 183 | ||
131 | /* Only for EXYNOS4210 */ | 184 | /* Only for EXYNOS4210 */ |
132 | #define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154 | 185 | #define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154 |
@@ -185,11 +238,116 @@ | |||
185 | #define S5P_DIS_IRQ_CORE3 0x1034 | 238 | #define S5P_DIS_IRQ_CORE3 0x1034 |
186 | #define S5P_DIS_IRQ_CENTRAL3 0x1038 | 239 | #define S5P_DIS_IRQ_CENTRAL3 0x1038 |
187 | 240 | ||
241 | /* Only for EXYNOS3XXX */ | ||
242 | #define EXYNOS3_ARM_CORE0_SYS_PWR_REG 0x1000 | ||
243 | #define EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG 0x1004 | ||
244 | #define EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG 0x1008 | ||
245 | #define EXYNOS3_ARM_CORE1_SYS_PWR_REG 0x1010 | ||
246 | #define EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG 0x1014 | ||
247 | #define EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG 0x1018 | ||
248 | #define EXYNOS3_ISP_ARM_SYS_PWR_REG 0x1050 | ||
249 | #define EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1054 | ||
250 | #define EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1058 | ||
251 | #define EXYNOS3_ARM_COMMON_SYS_PWR_REG 0x1080 | ||
252 | #define EXYNOS3_ARM_L2_SYS_PWR_REG 0x10C0 | ||
253 | #define EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG 0x1100 | ||
254 | #define EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG 0x1104 | ||
255 | #define EXYNOS3_CMU_RESET_SYS_PWR_REG 0x110C | ||
256 | #define EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG 0x1110 | ||
257 | #define EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG 0x1114 | ||
258 | #define EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG 0x111C | ||
259 | #define EXYNOS3_APLL_SYSCLK_SYS_PWR_REG 0x1120 | ||
260 | #define EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG 0x1124 | ||
261 | #define EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG 0x1128 | ||
262 | #define EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG 0x112C | ||
263 | #define EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG 0x1130 | ||
264 | #define EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG 0x1134 | ||
265 | #define EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG 0x1138 | ||
266 | #define EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140 | ||
267 | #define EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148 | ||
268 | #define EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C | ||
269 | #define EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150 | ||
270 | #define EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG 0x1154 | ||
271 | #define EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158 | ||
272 | #define EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG 0x1160 | ||
273 | #define EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG 0x1168 | ||
274 | #define EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG 0x116C | ||
275 | #define EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG 0x1170 | ||
276 | #define EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG 0x1174 | ||
277 | #define EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178 | ||
278 | #define EXYNOS3_TOP_BUS_SYS_PWR_REG 0x1180 | ||
279 | #define EXYNOS3_TOP_RETENTION_SYS_PWR_REG 0x1184 | ||
280 | #define EXYNOS3_TOP_PWR_SYS_PWR_REG 0x1188 | ||
281 | #define EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG 0x1190 | ||
282 | #define EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG 0x1194 | ||
283 | #define EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG 0x1198 | ||
284 | #define EXYNOS3_LOGIC_RESET_SYS_PWR_REG 0x11A0 | ||
285 | #define EXYNOS3_OSCCLK_GATE_SYS_PWR_REG 0x11A4 | ||
286 | #define EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG 0x11B0 | ||
287 | #define EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG 0x11B4 | ||
288 | #define EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200 | ||
289 | #define EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204 | ||
290 | #define EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG 0x1208 | ||
291 | #define EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1218 | ||
292 | #define EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220 | ||
293 | #define EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG 0x1224 | ||
294 | #define EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1228 | ||
295 | #define EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG 0x122C | ||
296 | #define EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230 | ||
297 | #define EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234 | ||
298 | #define EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1238 | ||
299 | #define EXYNOS3_PAD_ISOLATION_SYS_PWR_REG 0x1240 | ||
300 | #define EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG 0x1260 | ||
301 | #define EXYNOS3_XUSBXTI_SYS_PWR_REG 0x1280 | ||
302 | #define EXYNOS3_XXTI_SYS_PWR_REG 0x1284 | ||
303 | #define EXYNOS3_EXT_REGULATOR_SYS_PWR_REG 0x12C0 | ||
304 | #define EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG 0x12C4 | ||
305 | #define EXYNOS3_GPIO_MODE_SYS_PWR_REG 0x1300 | ||
306 | #define EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340 | ||
307 | #define EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG 0x1344 | ||
308 | #define EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG 0x1348 | ||
309 | #define EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG 0x1350 | ||
310 | #define EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG 0x1354 | ||
311 | #define EXYNOS3_CAM_SYS_PWR_REG 0x1380 | ||
312 | #define EXYNOS3_MFC_SYS_PWR_REG 0x1388 | ||
313 | #define EXYNOS3_G3D_SYS_PWR_REG 0x138C | ||
314 | #define EXYNOS3_LCD0_SYS_PWR_REG 0x1390 | ||
315 | #define EXYNOS3_ISP_SYS_PWR_REG 0x1394 | ||
316 | #define EXYNOS3_MAUDIO_SYS_PWR_REG 0x1398 | ||
317 | #define EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG 0x13B0 | ||
318 | #define EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG 0x13B4 | ||
319 | #define EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG 0x13B8 | ||
320 | #define EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG 0x13C0 | ||
321 | #define EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG 0x13C4 | ||
322 | #define EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG 0x13C8 | ||
323 | |||
324 | #define EXYNOS3_ARM_CORE0_OPTION 0x2008 | ||
325 | #define EXYNOS3_ARM_CORE_OPTION(_nr) \ | ||
326 | (EXYNOS3_ARM_CORE0_OPTION + ((_nr) * 0x80)) | ||
327 | |||
328 | #define EXYNOS3_ARM_COMMON_OPTION 0x2408 | ||
329 | #define EXYNOS3_TOP_PWR_OPTION 0x2C48 | ||
330 | #define EXYNOS3_CORE_TOP_PWR_OPTION 0x2CA8 | ||
331 | #define EXYNOS3_XUSBXTI_DURATION 0x341C | ||
332 | #define EXYNOS3_XXTI_DURATION 0x343C | ||
333 | #define EXYNOS3_EXT_REGULATOR_DURATION 0x361C | ||
334 | #define EXYNOS3_EXT_REGULATOR_COREBLK_DURATION 0x363C | ||
335 | #define XUSBXTI_DURATION 0x00000BB8 | ||
336 | #define XXTI_DURATION XUSBXTI_DURATION | ||
337 | #define EXT_REGULATOR_DURATION 0x00001D4C | ||
338 | #define EXT_REGULATOR_COREBLK_DURATION EXT_REGULATOR_DURATION | ||
339 | |||
340 | /* for XXX_OPTION */ | ||
341 | #define EXYNOS3_OPTION_USE_SC_COUNTER (1 << 0) | ||
342 | #define EXYNOS3_OPTION_USE_SC_FEEDBACK (1 << 1) | ||
343 | #define EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN (1 << 7) | ||
344 | |||
188 | /* For EXYNOS5 */ | 345 | /* For EXYNOS5 */ |
189 | 346 | ||
190 | #define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408 | 347 | #define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408 |
191 | #define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C | 348 | #define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C |
192 | 349 | ||
350 | #define EXYNOS5_USE_RETENTION BIT(4) | ||
193 | #define EXYNOS5_SYS_WDTRESET (1 << 20) | 351 | #define EXYNOS5_SYS_WDTRESET (1 << 20) |
194 | 352 | ||
195 | #define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000 | 353 | #define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000 |
@@ -329,4 +487,204 @@ static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr) | |||
329 | + MPIDR_AFFINITY_LEVEL(mpidr, 0)); | 487 | + MPIDR_AFFINITY_LEVEL(mpidr, 0)); |
330 | } | 488 | } |
331 | 489 | ||
490 | /* Only for EXYNOS5420 */ | ||
491 | #define EXYNOS5420_ISP_ARM_OPTION 0x2488 | ||
492 | #define EXYNOS5420_L2RSTDISABLE_VALUE BIT(3) | ||
493 | |||
494 | #define EXYNOS5420_LPI_MASK 0x0004 | ||
495 | #define EXYNOS5420_LPI_MASK1 0x0008 | ||
496 | #define EXYNOS5420_UFS BIT(8) | ||
497 | #define EXYNOS5420_ATB_KFC BIT(13) | ||
498 | #define EXYNOS5420_ATB_ISP_ARM BIT(19) | ||
499 | #define EXYNOS5420_EMULATION BIT(31) | ||
500 | #define ATB_ISP_ARM BIT(12) | ||
501 | #define ATB_KFC BIT(13) | ||
502 | #define ATB_NOC BIT(14) | ||
503 | |||
504 | #define EXYNOS5420_ARM_INTR_SPREAD_ENABLE 0x0100 | ||
505 | #define EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI 0x0104 | ||
506 | #define EXYNOS5420_UP_SCHEDULER 0x0120 | ||
507 | #define SPREAD_ENABLE 0xF | ||
508 | #define SPREAD_USE_STANDWFI 0xF | ||
509 | |||
510 | #define EXYNOS5420_BB_CON1 0x0784 | ||
511 | #define EXYNOS5420_BB_SEL_EN BIT(31) | ||
512 | #define EXYNOS5420_BB_PMOS_EN BIT(7) | ||
513 | #define EXYNOS5420_BB_1300X 0XF | ||
514 | |||
515 | #define EXYNOS5420_ARM_CORE2_SYS_PWR_REG 0x1020 | ||
516 | #define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024 | ||
517 | #define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028 | ||
518 | #define EXYNOS5420_ARM_CORE3_SYS_PWR_REG 0x1030 | ||
519 | #define EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG 0x1034 | ||
520 | #define EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG 0x1038 | ||
521 | #define EXYNOS5420_KFC_CORE0_SYS_PWR_REG 0x1040 | ||
522 | #define EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG 0x1044 | ||
523 | #define EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG 0x1048 | ||
524 | #define EXYNOS5420_KFC_CORE1_SYS_PWR_REG 0x1050 | ||
525 | #define EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG 0x1054 | ||
526 | #define EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG 0x1058 | ||
527 | #define EXYNOS5420_KFC_CORE2_SYS_PWR_REG 0x1060 | ||
528 | #define EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG 0x1064 | ||
529 | #define EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG 0x1068 | ||
530 | #define EXYNOS5420_KFC_CORE3_SYS_PWR_REG 0x1070 | ||
531 | #define EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG 0x1074 | ||
532 | #define EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG 0x1078 | ||
533 | #define EXYNOS5420_ISP_ARM_SYS_PWR_REG 0x1090 | ||
534 | #define EXYNOS5420_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1094 | ||
535 | #define EXYNOS5420_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1098 | ||
536 | #define EXYNOS5420_ARM_COMMON_SYS_PWR_REG 0x10A0 | ||
537 | #define EXYNOS5420_KFC_COMMON_SYS_PWR_REG 0x10B0 | ||
538 | #define EXYNOS5420_KFC_L2_SYS_PWR_REG 0x10D0 | ||
539 | #define EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG 0x1158 | ||
540 | #define EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG 0x115C | ||
541 | #define EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG 0x1160 | ||
542 | #define EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG 0x1174 | ||
543 | #define EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG 0x1178 | ||
544 | #define EXYNOS5420_INTRAM_MEM_SYS_PWR_REG 0x11B8 | ||
545 | #define EXYNOS5420_INTROM_MEM_SYS_PWR_REG 0x11BC | ||
546 | #define EXYNOS5420_ONENANDXL_MEM_SYS_PWR 0x11C0 | ||
547 | #define EXYNOS5420_USBDEV_MEM_SYS_PWR 0x11CC | ||
548 | #define EXYNOS5420_USBDEV1_MEM_SYS_PWR 0x11D0 | ||
549 | #define EXYNOS5420_SDMMC_MEM_SYS_PWR 0x11D4 | ||
550 | #define EXYNOS5420_CSSYS_MEM_SYS_PWR 0x11D8 | ||
551 | #define EXYNOS5420_SECSS_MEM_SYS_PWR 0x11DC | ||
552 | #define EXYNOS5420_ROTATOR_MEM_SYS_PWR 0x11E0 | ||
553 | #define EXYNOS5420_INTRAM_MEM_SYS_PWR 0x11E4 | ||
554 | #define EXYNOS5420_INTROM_MEM_SYS_PWR 0x11E8 | ||
555 | #define EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1208 | ||
556 | #define EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1210 | ||
557 | #define EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG 0x1214 | ||
558 | #define EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1218 | ||
559 | #define EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG 0x121C | ||
560 | #define EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1220 | ||
561 | #define EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG 0x1224 | ||
562 | #define EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1228 | ||
563 | #define EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG 0x122C | ||
564 | #define EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG 0x1230 | ||
565 | #define EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG 0x1234 | ||
566 | #define EXYNOS5420_DISP1_SYS_PWR_REG 0x1410 | ||
567 | #define EXYNOS5420_MAU_SYS_PWR_REG 0x1414 | ||
568 | #define EXYNOS5420_G2D_SYS_PWR_REG 0x1418 | ||
569 | #define EXYNOS5420_MSC_SYS_PWR_REG 0x141C | ||
570 | #define EXYNOS5420_FSYS_SYS_PWR_REG 0x1420 | ||
571 | #define EXYNOS5420_FSYS2_SYS_PWR_REG 0x1424 | ||
572 | #define EXYNOS5420_PSGEN_SYS_PWR_REG 0x1428 | ||
573 | #define EXYNOS5420_PERIC_SYS_PWR_REG 0x142C | ||
574 | #define EXYNOS5420_WCORE_SYS_PWR_REG 0x1430 | ||
575 | #define EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG 0x1490 | ||
576 | #define EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG 0x1494 | ||
577 | #define EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG 0x1498 | ||
578 | #define EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG 0x149C | ||
579 | #define EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG 0x14A0 | ||
580 | #define EXYNOS5420_CMU_CLKSTOP_FSYS2_SYS_PWR_REG 0x14A4 | ||
581 | #define EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG 0x14A8 | ||
582 | #define EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG 0x14AC | ||
583 | #define EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG 0x14B0 | ||
584 | #define EXYNOS5420_CMU_SYSCLK_TOPPWR_SYS_PWR_REG 0x14BC | ||
585 | #define EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG 0x14D0 | ||
586 | #define EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG 0x14D4 | ||
587 | #define EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG 0x14D8 | ||
588 | #define EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG 0x14DC | ||
589 | #define EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG 0x14E0 | ||
590 | #define EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG 0x14E4 | ||
591 | #define EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG 0x14E8 | ||
592 | #define EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG 0x14EC | ||
593 | #define EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG 0x14F0 | ||
594 | #define EXYNOS5420_CMU_SYSCLK_SYSMEM_TOPPWR_SYS_PWR_REG 0x14F4 | ||
595 | #define EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG 0x1570 | ||
596 | #define EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG 0x1574 | ||
597 | #define EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG 0x1578 | ||
598 | #define EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG 0x157C | ||
599 | #define EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG 0x1590 | ||
600 | #define EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG 0x1594 | ||
601 | #define EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG 0x1598 | ||
602 | #define EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG 0x159C | ||
603 | #define EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG 0x15A0 | ||
604 | #define EXYNOS5420_SFR_AXI_CGDIS1 0x15E4 | ||
605 | #define EXYNOS_ARM_CORE2_CONFIGURATION 0x2100 | ||
606 | #define EXYNOS5420_ARM_CORE2_OPTION 0x2108 | ||
607 | #define EXYNOS_ARM_CORE3_CONFIGURATION 0x2180 | ||
608 | #define EXYNOS5420_ARM_CORE3_OPTION 0x2188 | ||
609 | #define EXYNOS5420_ARM_COMMON_STATUS 0x2504 | ||
610 | #define EXYNOS5420_ARM_COMMON_OPTION 0x2508 | ||
611 | #define EXYNOS5420_KFC_COMMON_STATUS 0x2584 | ||
612 | #define EXYNOS5420_KFC_COMMON_OPTION 0x2588 | ||
613 | #define EXYNOS5420_LOGIC_RESET_DURATION3 0x2D1C | ||
614 | |||
615 | #define EXYNOS5420_PAD_RET_GPIO_OPTION 0x30C8 | ||
616 | #define EXYNOS5420_PAD_RET_UART_OPTION 0x30E8 | ||
617 | #define EXYNOS5420_PAD_RET_MMCA_OPTION 0x3108 | ||
618 | #define EXYNOS5420_PAD_RET_MMCB_OPTION 0x3128 | ||
619 | #define EXYNOS5420_PAD_RET_MMCC_OPTION 0x3148 | ||
620 | #define EXYNOS5420_PAD_RET_HSI_OPTION 0x3168 | ||
621 | #define EXYNOS5420_PAD_RET_SPI_OPTION 0x31C8 | ||
622 | #define EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION 0x31E8 | ||
623 | #define EXYNOS_PAD_RET_DRAM_OPTION 0x3008 | ||
624 | #define EXYNOS_PAD_RET_MAUDIO_OPTION 0x3028 | ||
625 | #define EXYNOS_PAD_RET_JTAG_OPTION 0x3048 | ||
626 | #define EXYNOS_PAD_RET_GPIO_OPTION 0x3108 | ||
627 | #define EXYNOS_PAD_RET_UART_OPTION 0x3128 | ||
628 | #define EXYNOS_PAD_RET_MMCA_OPTION 0x3148 | ||
629 | #define EXYNOS_PAD_RET_MMCB_OPTION 0x3168 | ||
630 | #define EXYNOS_PAD_RET_EBIA_OPTION 0x3188 | ||
631 | #define EXYNOS_PAD_RET_EBIB_OPTION 0x31A8 | ||
632 | |||
633 | #define EXYNOS_PS_HOLD_CONTROL 0x330C | ||
634 | |||
635 | /* For SYS_PWR_REG */ | ||
636 | #define EXYNOS_SYS_PWR_CFG BIT(0) | ||
637 | |||
638 | #define EXYNOS5420_MFC_CONFIGURATION 0x4060 | ||
639 | #define EXYNOS5420_MFC_STATUS 0x4064 | ||
640 | #define EXYNOS5420_MFC_OPTION 0x4068 | ||
641 | #define EXYNOS5420_G3D_CONFIGURATION 0x4080 | ||
642 | #define EXYNOS5420_G3D_STATUS 0x4084 | ||
643 | #define EXYNOS5420_G3D_OPTION 0x4088 | ||
644 | #define EXYNOS5420_DISP0_CONFIGURATION 0x40A0 | ||
645 | #define EXYNOS5420_DISP0_STATUS 0x40A4 | ||
646 | #define EXYNOS5420_DISP0_OPTION 0x40A8 | ||
647 | #define EXYNOS5420_DISP1_CONFIGURATION 0x40C0 | ||
648 | #define EXYNOS5420_DISP1_STATUS 0x40C4 | ||
649 | #define EXYNOS5420_DISP1_OPTION 0x40C8 | ||
650 | #define EXYNOS5420_MAU_CONFIGURATION 0x40E0 | ||
651 | #define EXYNOS5420_MAU_STATUS 0x40E4 | ||
652 | #define EXYNOS5420_MAU_OPTION 0x40E8 | ||
653 | #define EXYNOS5420_FSYS2_OPTION 0x4168 | ||
654 | #define EXYNOS5420_PSGEN_OPTION 0x4188 | ||
655 | |||
656 | /* For EXYNOS_CENTRAL_SEQ_OPTION */ | ||
657 | #define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 BIT(16) | ||
658 | #define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 BUT(17) | ||
659 | #define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 BIT(24) | ||
660 | #define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 BIT(25) | ||
661 | |||
662 | #define EXYNOS5420_ARM_USE_STANDBY_WFI0 BIT(4) | ||
663 | #define EXYNOS5420_ARM_USE_STANDBY_WFI1 BIT(5) | ||
664 | #define EXYNOS5420_ARM_USE_STANDBY_WFI2 BIT(6) | ||
665 | #define EXYNOS5420_ARM_USE_STANDBY_WFI3 BIT(7) | ||
666 | #define EXYNOS5420_KFC_USE_STANDBY_WFI0 BIT(8) | ||
667 | #define EXYNOS5420_KFC_USE_STANDBY_WFI1 BIT(9) | ||
668 | #define EXYNOS5420_KFC_USE_STANDBY_WFI2 BIT(10) | ||
669 | #define EXYNOS5420_KFC_USE_STANDBY_WFI3 BIT(11) | ||
670 | #define EXYNOS5420_ARM_USE_STANDBY_WFE0 BIT(16) | ||
671 | #define EXYNOS5420_ARM_USE_STANDBY_WFE1 BIT(17) | ||
672 | #define EXYNOS5420_ARM_USE_STANDBY_WFE2 BIT(18) | ||
673 | #define EXYNOS5420_ARM_USE_STANDBY_WFE3 BIT(19) | ||
674 | #define EXYNOS5420_KFC_USE_STANDBY_WFE0 BIT(20) | ||
675 | #define EXYNOS5420_KFC_USE_STANDBY_WFE1 BIT(21) | ||
676 | #define EXYNOS5420_KFC_USE_STANDBY_WFE2 BIT(22) | ||
677 | #define EXYNOS5420_KFC_USE_STANDBY_WFE3 BIT(23) | ||
678 | |||
679 | #define DUR_WAIT_RESET 0xF | ||
680 | |||
681 | #define EXYNOS5420_USE_STANDBY_WFI_ALL (EXYNOS5420_ARM_USE_STANDBY_WFI0 \ | ||
682 | | EXYNOS5420_ARM_USE_STANDBY_WFI1 \ | ||
683 | | EXYNOS5420_ARM_USE_STANDBY_WFI2 \ | ||
684 | | EXYNOS5420_ARM_USE_STANDBY_WFI3 \ | ||
685 | | EXYNOS5420_KFC_USE_STANDBY_WFI0 \ | ||
686 | | EXYNOS5420_KFC_USE_STANDBY_WFI1 \ | ||
687 | | EXYNOS5420_KFC_USE_STANDBY_WFI2 \ | ||
688 | | EXYNOS5420_KFC_USE_STANDBY_WFI3) | ||
689 | |||
332 | #endif /* __ASM_ARCH_REGS_PMU_H */ | 690 | #endif /* __ASM_ARCH_REGS_PMU_H */ |
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S index 108a45f4bb62..e3c373082bbe 100644 --- a/arch/arm/mach-exynos/sleep.S +++ b/arch/arm/mach-exynos/sleep.S | |||
@@ -16,6 +16,7 @@ | |||
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/linkage.h> | 18 | #include <linux/linkage.h> |
19 | #include "smc.h" | ||
19 | 20 | ||
20 | #define CPU_MASK 0xff0ffff0 | 21 | #define CPU_MASK 0xff0ffff0 |
21 | #define CPU_CORTEX_A9 0x410fc090 | 22 | #define CPU_CORTEX_A9 0x410fc090 |
@@ -55,3 +56,30 @@ ENTRY(exynos_cpu_resume) | |||
55 | #endif | 56 | #endif |
56 | b cpu_resume | 57 | b cpu_resume |
57 | ENDPROC(exynos_cpu_resume) | 58 | ENDPROC(exynos_cpu_resume) |
59 | |||
60 | .align | ||
61 | |||
62 | ENTRY(exynos_cpu_resume_ns) | ||
63 | mrc p15, 0, r0, c0, c0, 0 | ||
64 | ldr r1, =CPU_MASK | ||
65 | and r0, r0, r1 | ||
66 | ldr r1, =CPU_CORTEX_A9 | ||
67 | cmp r0, r1 | ||
68 | bne skip_cp15 | ||
69 | |||
70 | adr r0, cp15_save_power | ||
71 | ldr r1, [r0] | ||
72 | adr r0, cp15_save_diag | ||
73 | ldr r2, [r0] | ||
74 | mov r0, #SMC_CMD_C15RESUME | ||
75 | dsb | ||
76 | smc #0 | ||
77 | skip_cp15: | ||
78 | b cpu_resume | ||
79 | ENDPROC(exynos_cpu_resume_ns) | ||
80 | .globl cp15_save_diag | ||
81 | cp15_save_diag: | ||
82 | .long 0 @ cp15 diagnostic | ||
83 | .globl cp15_save_power | ||
84 | cp15_save_power: | ||
85 | .long 0 @ cp15 power control | ||
diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h index 13a1dc8ecbf2..f7b82f9c1e21 100644 --- a/arch/arm/mach-exynos/smc.h +++ b/arch/arm/mach-exynos/smc.h | |||
@@ -26,6 +26,10 @@ | |||
26 | #define SMC_CMD_L2X0INVALL (-24) | 26 | #define SMC_CMD_L2X0INVALL (-24) |
27 | #define SMC_CMD_L2X0DEBUG (-25) | 27 | #define SMC_CMD_L2X0DEBUG (-25) |
28 | 28 | ||
29 | #ifndef __ASSEMBLY__ | ||
30 | |||
29 | extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); | 31 | extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3); |
30 | 32 | ||
33 | #endif /* __ASSEMBLY__ */ | ||
34 | |||
31 | #endif | 35 | #endif |
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c new file mode 100644 index 000000000000..f8e7dcd17055 --- /dev/null +++ b/arch/arm/mach-exynos/suspend.c | |||
@@ -0,0 +1,566 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd. | ||
3 | * http://www.samsung.com | ||
4 | * | ||
5 | * EXYNOS - Suspend support | ||
6 | * | ||
7 | * Based on arch/arm/mach-s3c2410/pm.c | ||
8 | * Copyright (c) 2006 Simtec Electronics | ||
9 | * Ben Dooks <ben@simtec.co.uk> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/suspend.h> | ||
18 | #include <linux/syscore_ops.h> | ||
19 | #include <linux/cpu_pm.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/irqchip/arm-gic.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/regulator/machine.h> | ||
24 | |||
25 | #include <asm/cacheflush.h> | ||
26 | #include <asm/hardware/cache-l2x0.h> | ||
27 | #include <asm/firmware.h> | ||
28 | #include <asm/mcpm.h> | ||
29 | #include <asm/smp_scu.h> | ||
30 | #include <asm/suspend.h> | ||
31 | |||
32 | #include <plat/pm-common.h> | ||
33 | #include <plat/regs-srom.h> | ||
34 | |||
35 | #include "common.h" | ||
36 | #include "regs-pmu.h" | ||
37 | #include "regs-sys.h" | ||
38 | #include "exynos-pmu.h" | ||
39 | |||
40 | #define S5P_CHECK_SLEEP 0x00000BAD | ||
41 | |||
42 | #define REG_TABLE_END (-1U) | ||
43 | |||
44 | #define EXYNOS5420_CPU_STATE 0x28 | ||
45 | |||
46 | /** | ||
47 | * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping | ||
48 | * @hwirq: Hardware IRQ signal of the GIC | ||
49 | * @mask: Mask in PMU wake-up mask register | ||
50 | */ | ||
51 | struct exynos_wkup_irq { | ||
52 | unsigned int hwirq; | ||
53 | u32 mask; | ||
54 | }; | ||
55 | |||
56 | static struct sleep_save exynos5_sys_save[] = { | ||
57 | SAVE_ITEM(EXYNOS5_SYS_I2C_CFG), | ||
58 | }; | ||
59 | |||
60 | static struct sleep_save exynos_core_save[] = { | ||
61 | /* SROM side */ | ||
62 | SAVE_ITEM(S5P_SROM_BW), | ||
63 | SAVE_ITEM(S5P_SROM_BC0), | ||
64 | SAVE_ITEM(S5P_SROM_BC1), | ||
65 | SAVE_ITEM(S5P_SROM_BC2), | ||
66 | SAVE_ITEM(S5P_SROM_BC3), | ||
67 | }; | ||
68 | |||
69 | struct exynos_pm_data { | ||
70 | const struct exynos_wkup_irq *wkup_irq; | ||
71 | struct sleep_save *extra_save; | ||
72 | int num_extra_save; | ||
73 | unsigned int wake_disable_mask; | ||
74 | unsigned int *release_ret_regs; | ||
75 | |||
76 | void (*pm_prepare)(void); | ||
77 | void (*pm_resume_prepare)(void); | ||
78 | void (*pm_resume)(void); | ||
79 | int (*pm_suspend)(void); | ||
80 | int (*cpu_suspend)(unsigned long); | ||
81 | }; | ||
82 | |||
83 | struct exynos_pm_data *pm_data; | ||
84 | |||
85 | static int exynos5420_cpu_state; | ||
86 | static unsigned int exynos_pmu_spare3; | ||
87 | |||
88 | /* | ||
89 | * GIC wake-up support | ||
90 | */ | ||
91 | |||
92 | static u32 exynos_irqwake_intmask = 0xffffffff; | ||
93 | |||
94 | static const struct exynos_wkup_irq exynos4_wkup_irq[] = { | ||
95 | { 76, BIT(1) }, /* RTC alarm */ | ||
96 | { 77, BIT(2) }, /* RTC tick */ | ||
97 | { /* sentinel */ }, | ||
98 | }; | ||
99 | |||
100 | static const struct exynos_wkup_irq exynos5250_wkup_irq[] = { | ||
101 | { 75, BIT(1) }, /* RTC alarm */ | ||
102 | { 76, BIT(2) }, /* RTC tick */ | ||
103 | { /* sentinel */ }, | ||
104 | }; | ||
105 | |||
106 | unsigned int exynos_release_ret_regs[] = { | ||
107 | S5P_PAD_RET_MAUDIO_OPTION, | ||
108 | S5P_PAD_RET_GPIO_OPTION, | ||
109 | S5P_PAD_RET_UART_OPTION, | ||
110 | S5P_PAD_RET_MMCA_OPTION, | ||
111 | S5P_PAD_RET_MMCB_OPTION, | ||
112 | S5P_PAD_RET_EBIA_OPTION, | ||
113 | S5P_PAD_RET_EBIB_OPTION, | ||
114 | REG_TABLE_END, | ||
115 | }; | ||
116 | |||
117 | unsigned int exynos5420_release_ret_regs[] = { | ||
118 | EXYNOS_PAD_RET_DRAM_OPTION, | ||
119 | EXYNOS_PAD_RET_MAUDIO_OPTION, | ||
120 | EXYNOS_PAD_RET_JTAG_OPTION, | ||
121 | EXYNOS5420_PAD_RET_GPIO_OPTION, | ||
122 | EXYNOS5420_PAD_RET_UART_OPTION, | ||
123 | EXYNOS5420_PAD_RET_MMCA_OPTION, | ||
124 | EXYNOS5420_PAD_RET_MMCB_OPTION, | ||
125 | EXYNOS5420_PAD_RET_MMCC_OPTION, | ||
126 | EXYNOS5420_PAD_RET_HSI_OPTION, | ||
127 | EXYNOS_PAD_RET_EBIA_OPTION, | ||
128 | EXYNOS_PAD_RET_EBIB_OPTION, | ||
129 | EXYNOS5420_PAD_RET_SPI_OPTION, | ||
130 | EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION, | ||
131 | REG_TABLE_END, | ||
132 | }; | ||
133 | |||
134 | static int exynos_irq_set_wake(struct irq_data *data, unsigned int state) | ||
135 | { | ||
136 | const struct exynos_wkup_irq *wkup_irq; | ||
137 | |||
138 | if (!pm_data->wkup_irq) | ||
139 | return -ENOENT; | ||
140 | wkup_irq = pm_data->wkup_irq; | ||
141 | |||
142 | while (wkup_irq->mask) { | ||
143 | if (wkup_irq->hwirq == data->hwirq) { | ||
144 | if (!state) | ||
145 | exynos_irqwake_intmask |= wkup_irq->mask; | ||
146 | else | ||
147 | exynos_irqwake_intmask &= ~wkup_irq->mask; | ||
148 | return 0; | ||
149 | } | ||
150 | ++wkup_irq; | ||
151 | } | ||
152 | |||
153 | return -ENOENT; | ||
154 | } | ||
155 | |||
156 | static int exynos_cpu_do_idle(void) | ||
157 | { | ||
158 | /* issue the standby signal into the pm unit. */ | ||
159 | cpu_do_idle(); | ||
160 | |||
161 | pr_info("Failed to suspend the system\n"); | ||
162 | return 1; /* Aborting suspend */ | ||
163 | } | ||
164 | static void exynos_flush_cache_all(void) | ||
165 | { | ||
166 | flush_cache_all(); | ||
167 | outer_flush_all(); | ||
168 | } | ||
169 | |||
170 | static int exynos_cpu_suspend(unsigned long arg) | ||
171 | { | ||
172 | exynos_flush_cache_all(); | ||
173 | return exynos_cpu_do_idle(); | ||
174 | } | ||
175 | |||
176 | static int exynos5420_cpu_suspend(unsigned long arg) | ||
177 | { | ||
178 | /* MCPM works with HW CPU identifiers */ | ||
179 | unsigned int mpidr = read_cpuid_mpidr(); | ||
180 | unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1); | ||
181 | unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0); | ||
182 | |||
183 | __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE); | ||
184 | |||
185 | if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) { | ||
186 | mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume); | ||
187 | |||
188 | /* | ||
189 | * Residency value passed to mcpm_cpu_suspend back-end | ||
190 | * has to be given clear semantics. Set to 0 as a | ||
191 | * temporary value. | ||
192 | */ | ||
193 | mcpm_cpu_suspend(0); | ||
194 | } | ||
195 | |||
196 | pr_info("Failed to suspend the system\n"); | ||
197 | |||
198 | /* return value != 0 means failure */ | ||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | static void exynos_pm_set_wakeup_mask(void) | ||
203 | { | ||
204 | /* Set wake-up mask registers */ | ||
205 | pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK); | ||
206 | pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK); | ||
207 | } | ||
208 | |||
209 | static void exynos_pm_enter_sleep_mode(void) | ||
210 | { | ||
211 | /* Set value of power down register for sleep mode */ | ||
212 | exynos_sys_powerdown_conf(SYS_SLEEP); | ||
213 | pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1); | ||
214 | } | ||
215 | |||
216 | static void exynos_pm_prepare(void) | ||
217 | { | ||
218 | /* Set wake-up mask registers */ | ||
219 | exynos_pm_set_wakeup_mask(); | ||
220 | |||
221 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
222 | |||
223 | if (pm_data->extra_save) | ||
224 | s3c_pm_do_save(pm_data->extra_save, | ||
225 | pm_data->num_extra_save); | ||
226 | |||
227 | exynos_pm_enter_sleep_mode(); | ||
228 | |||
229 | /* ensure at least INFORM0 has the resume address */ | ||
230 | pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0); | ||
231 | } | ||
232 | |||
233 | static void exynos5420_pm_prepare(void) | ||
234 | { | ||
235 | unsigned int tmp; | ||
236 | |||
237 | /* Set wake-up mask registers */ | ||
238 | exynos_pm_set_wakeup_mask(); | ||
239 | |||
240 | s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
241 | |||
242 | exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3); | ||
243 | /* | ||
244 | * The cpu state needs to be saved and restored so that the | ||
245 | * secondary CPUs will enter low power start. Though the U-Boot | ||
246 | * is setting the cpu state with low power flag, the kernel | ||
247 | * needs to restore it back in case, the primary cpu fails to | ||
248 | * suspend for any reason. | ||
249 | */ | ||
250 | exynos5420_cpu_state = __raw_readl(sysram_base_addr + | ||
251 | EXYNOS5420_CPU_STATE); | ||
252 | |||
253 | exynos_pm_enter_sleep_mode(); | ||
254 | |||
255 | /* ensure at least INFORM0 has the resume address */ | ||
256 | if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) | ||
257 | pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0); | ||
258 | |||
259 | tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION); | ||
260 | tmp &= ~EXYNOS5_USE_RETENTION; | ||
261 | pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION); | ||
262 | |||
263 | tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); | ||
264 | tmp |= EXYNOS5420_UFS; | ||
265 | pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); | ||
266 | |||
267 | tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION); | ||
268 | tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE; | ||
269 | pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION); | ||
270 | |||
271 | tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); | ||
272 | tmp |= EXYNOS5420_EMULATION; | ||
273 | pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); | ||
274 | |||
275 | tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); | ||
276 | tmp |= EXYNOS5420_EMULATION; | ||
277 | pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); | ||
278 | } | ||
279 | |||
280 | |||
281 | static int exynos_pm_suspend(void) | ||
282 | { | ||
283 | exynos_pm_central_suspend(); | ||
284 | |||
285 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) | ||
286 | exynos_cpu_save_register(); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int exynos5420_pm_suspend(void) | ||
292 | { | ||
293 | u32 this_cluster; | ||
294 | |||
295 | exynos_pm_central_suspend(); | ||
296 | |||
297 | /* Setting SEQ_OPTION register */ | ||
298 | |||
299 | this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1); | ||
300 | if (!this_cluster) | ||
301 | pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0, | ||
302 | S5P_CENTRAL_SEQ_OPTION); | ||
303 | else | ||
304 | pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0, | ||
305 | S5P_CENTRAL_SEQ_OPTION); | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void exynos_pm_release_retention(void) | ||
310 | { | ||
311 | unsigned int i; | ||
312 | |||
313 | for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++) | ||
314 | pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR, | ||
315 | pm_data->release_ret_regs[i]); | ||
316 | } | ||
317 | |||
318 | static void exynos_pm_resume(void) | ||
319 | { | ||
320 | u32 cpuid = read_cpuid_part(); | ||
321 | |||
322 | if (exynos_pm_central_resume()) | ||
323 | goto early_wakeup; | ||
324 | |||
325 | /* For release retention */ | ||
326 | exynos_pm_release_retention(); | ||
327 | |||
328 | if (pm_data->extra_save) | ||
329 | s3c_pm_do_restore_core(pm_data->extra_save, | ||
330 | pm_data->num_extra_save); | ||
331 | |||
332 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
333 | |||
334 | if (cpuid == ARM_CPU_PART_CORTEX_A9) | ||
335 | scu_enable(S5P_VA_SCU); | ||
336 | |||
337 | if (call_firmware_op(resume) == -ENOSYS | ||
338 | && cpuid == ARM_CPU_PART_CORTEX_A9) | ||
339 | exynos_cpu_restore_register(); | ||
340 | |||
341 | early_wakeup: | ||
342 | |||
343 | /* Clear SLEEP mode set in INFORM1 */ | ||
344 | pmu_raw_writel(0x0, S5P_INFORM1); | ||
345 | } | ||
346 | |||
347 | static void exynos5420_prepare_pm_resume(void) | ||
348 | { | ||
349 | if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) | ||
350 | WARN_ON(mcpm_cpu_powered_up()); | ||
351 | } | ||
352 | |||
353 | static void exynos5420_pm_resume(void) | ||
354 | { | ||
355 | unsigned long tmp; | ||
356 | |||
357 | /* Restore the CPU0 low power state register */ | ||
358 | tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG); | ||
359 | pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN, | ||
360 | EXYNOS5_ARM_CORE0_SYS_PWR_REG); | ||
361 | |||
362 | /* Restore the sysram cpu state register */ | ||
363 | __raw_writel(exynos5420_cpu_state, | ||
364 | sysram_base_addr + EXYNOS5420_CPU_STATE); | ||
365 | |||
366 | pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, | ||
367 | S5P_CENTRAL_SEQ_OPTION); | ||
368 | |||
369 | if (exynos_pm_central_resume()) | ||
370 | goto early_wakeup; | ||
371 | |||
372 | /* For release retention */ | ||
373 | exynos_pm_release_retention(); | ||
374 | |||
375 | pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3); | ||
376 | |||
377 | s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save)); | ||
378 | |||
379 | early_wakeup: | ||
380 | |||
381 | tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1); | ||
382 | tmp &= ~EXYNOS5420_UFS; | ||
383 | pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1); | ||
384 | |||
385 | tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION); | ||
386 | tmp &= ~EXYNOS5420_EMULATION; | ||
387 | pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION); | ||
388 | |||
389 | tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION); | ||
390 | tmp &= ~EXYNOS5420_EMULATION; | ||
391 | pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION); | ||
392 | |||
393 | /* Clear SLEEP mode set in INFORM1 */ | ||
394 | pmu_raw_writel(0x0, S5P_INFORM1); | ||
395 | } | ||
396 | |||
397 | /* | ||
398 | * Suspend Ops | ||
399 | */ | ||
400 | |||
401 | static int exynos_suspend_enter(suspend_state_t state) | ||
402 | { | ||
403 | int ret; | ||
404 | |||
405 | s3c_pm_debug_init(); | ||
406 | |||
407 | S3C_PMDBG("%s: suspending the system...\n", __func__); | ||
408 | |||
409 | S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__, | ||
410 | exynos_irqwake_intmask, exynos_get_eint_wake_mask()); | ||
411 | |||
412 | if (exynos_irqwake_intmask == -1U | ||
413 | && exynos_get_eint_wake_mask() == -1U) { | ||
414 | pr_err("%s: No wake-up sources!\n", __func__); | ||
415 | pr_err("%s: Aborting sleep\n", __func__); | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | |||
419 | s3c_pm_save_uarts(); | ||
420 | if (pm_data->pm_prepare) | ||
421 | pm_data->pm_prepare(); | ||
422 | flush_cache_all(); | ||
423 | s3c_pm_check_store(); | ||
424 | |||
425 | ret = call_firmware_op(suspend); | ||
426 | if (ret == -ENOSYS) | ||
427 | ret = cpu_suspend(0, pm_data->cpu_suspend); | ||
428 | if (ret) | ||
429 | return ret; | ||
430 | |||
431 | if (pm_data->pm_resume_prepare) | ||
432 | pm_data->pm_resume_prepare(); | ||
433 | s3c_pm_restore_uarts(); | ||
434 | |||
435 | S3C_PMDBG("%s: wakeup stat: %08x\n", __func__, | ||
436 | pmu_raw_readl(S5P_WAKEUP_STAT)); | ||
437 | |||
438 | s3c_pm_check_restore(); | ||
439 | |||
440 | S3C_PMDBG("%s: resuming the system...\n", __func__); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int exynos_suspend_prepare(void) | ||
446 | { | ||
447 | int ret; | ||
448 | |||
449 | /* | ||
450 | * REVISIT: It would be better if struct platform_suspend_ops | ||
451 | * .prepare handler get the suspend_state_t as a parameter to | ||
452 | * avoid hard-coding the suspend to mem state. It's safe to do | ||
453 | * it now only because the suspend_valid_only_mem function is | ||
454 | * used as the .valid callback used to check if a given state | ||
455 | * is supported by the platform anyways. | ||
456 | */ | ||
457 | ret = regulator_suspend_prepare(PM_SUSPEND_MEM); | ||
458 | if (ret) { | ||
459 | pr_err("Failed to prepare regulators for suspend (%d)\n", ret); | ||
460 | return ret; | ||
461 | } | ||
462 | |||
463 | s3c_pm_check_prepare(); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static void exynos_suspend_finish(void) | ||
469 | { | ||
470 | int ret; | ||
471 | |||
472 | s3c_pm_check_cleanup(); | ||
473 | |||
474 | ret = regulator_suspend_finish(); | ||
475 | if (ret) | ||
476 | pr_warn("Failed to resume regulators from suspend (%d)\n", ret); | ||
477 | } | ||
478 | |||
479 | static const struct platform_suspend_ops exynos_suspend_ops = { | ||
480 | .enter = exynos_suspend_enter, | ||
481 | .prepare = exynos_suspend_prepare, | ||
482 | .finish = exynos_suspend_finish, | ||
483 | .valid = suspend_valid_only_mem, | ||
484 | }; | ||
485 | |||
486 | static const struct exynos_pm_data exynos4_pm_data = { | ||
487 | .wkup_irq = exynos4_wkup_irq, | ||
488 | .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), | ||
489 | .release_ret_regs = exynos_release_ret_regs, | ||
490 | .pm_suspend = exynos_pm_suspend, | ||
491 | .pm_resume = exynos_pm_resume, | ||
492 | .pm_prepare = exynos_pm_prepare, | ||
493 | .cpu_suspend = exynos_cpu_suspend, | ||
494 | }; | ||
495 | |||
496 | static const struct exynos_pm_data exynos5250_pm_data = { | ||
497 | .wkup_irq = exynos5250_wkup_irq, | ||
498 | .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)), | ||
499 | .release_ret_regs = exynos_release_ret_regs, | ||
500 | .extra_save = exynos5_sys_save, | ||
501 | .num_extra_save = ARRAY_SIZE(exynos5_sys_save), | ||
502 | .pm_suspend = exynos_pm_suspend, | ||
503 | .pm_resume = exynos_pm_resume, | ||
504 | .pm_prepare = exynos_pm_prepare, | ||
505 | .cpu_suspend = exynos_cpu_suspend, | ||
506 | }; | ||
507 | |||
508 | static struct exynos_pm_data exynos5420_pm_data = { | ||
509 | .wkup_irq = exynos5250_wkup_irq, | ||
510 | .wake_disable_mask = (0x7F << 7) | (0x1F << 1), | ||
511 | .release_ret_regs = exynos5420_release_ret_regs, | ||
512 | .pm_resume_prepare = exynos5420_prepare_pm_resume, | ||
513 | .pm_resume = exynos5420_pm_resume, | ||
514 | .pm_suspend = exynos5420_pm_suspend, | ||
515 | .pm_prepare = exynos5420_pm_prepare, | ||
516 | .cpu_suspend = exynos5420_cpu_suspend, | ||
517 | }; | ||
518 | |||
519 | static struct of_device_id exynos_pmu_of_device_ids[] = { | ||
520 | { | ||
521 | .compatible = "samsung,exynos4210-pmu", | ||
522 | .data = &exynos4_pm_data, | ||
523 | }, { | ||
524 | .compatible = "samsung,exynos4212-pmu", | ||
525 | .data = &exynos4_pm_data, | ||
526 | }, { | ||
527 | .compatible = "samsung,exynos4412-pmu", | ||
528 | .data = &exynos4_pm_data, | ||
529 | }, { | ||
530 | .compatible = "samsung,exynos5250-pmu", | ||
531 | .data = &exynos5250_pm_data, | ||
532 | }, { | ||
533 | .compatible = "samsung,exynos5420-pmu", | ||
534 | .data = &exynos5420_pm_data, | ||
535 | }, | ||
536 | { /*sentinel*/ }, | ||
537 | }; | ||
538 | |||
539 | static struct syscore_ops exynos_pm_syscore_ops; | ||
540 | |||
541 | void __init exynos_pm_init(void) | ||
542 | { | ||
543 | const struct of_device_id *match; | ||
544 | u32 tmp; | ||
545 | |||
546 | of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match); | ||
547 | if (!match) { | ||
548 | pr_err("Failed to find PMU node\n"); | ||
549 | return; | ||
550 | } | ||
551 | pm_data = (struct exynos_pm_data *) match->data; | ||
552 | |||
553 | /* Platform-specific GIC callback */ | ||
554 | gic_arch_extn.irq_set_wake = exynos_irq_set_wake; | ||
555 | |||
556 | /* All wakeup disable */ | ||
557 | tmp = pmu_raw_readl(S5P_WAKEUP_MASK); | ||
558 | tmp |= pm_data->wake_disable_mask; | ||
559 | pmu_raw_writel(tmp, S5P_WAKEUP_MASK); | ||
560 | |||
561 | exynos_pm_syscore_ops.suspend = pm_data->pm_suspend; | ||
562 | exynos_pm_syscore_ops.resume = pm_data->pm_resume; | ||
563 | |||
564 | register_syscore_ops(&exynos_pm_syscore_ops); | ||
565 | suspend_set_ops(&exynos_suspend_ops); | ||
566 | } | ||