Commit | Line | Data |
---|---|---|
7d30e8b3 | 1 | /* linux arch/arm/mach-exynos4/hotplug.c |
11adcc29 CY |
2 | * |
3 | * Cloned from linux/arch/arm/mach-realview/hotplug.c | |
4 | * | |
5 | * Copyright (C) 2002 ARM Ltd. | |
6 | * All Rights Reserved | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/kernel.h> | |
14 | #include <linux/errno.h> | |
15 | #include <linux/smp.h> | |
911c29b0 | 16 | #include <linux/io.h> |
11adcc29 CY |
17 | |
18 | #include <asm/cacheflush.h> | |
15d07dc9 | 19 | #include <asm/cp15.h> |
eb50439b | 20 | #include <asm/smp_plat.h> |
11adcc29 | 21 | |
911c29b0 | 22 | #include <mach/regs-pmu.h> |
756e46db | 23 | #include <plat/cpu.h> |
911c29b0 | 24 | |
06853ae4 MZ |
25 | #include "common.h" |
26 | ||
756e46db | 27 | static inline void cpu_enter_lowpower_a9(void) |
11adcc29 CY |
28 | { |
29 | unsigned int v; | |
30 | ||
31 | flush_cache_all(); | |
32 | asm volatile( | |
33 | " mcr p15, 0, %1, c7, c5, 0\n" | |
34 | " mcr p15, 0, %1, c7, c10, 4\n" | |
35 | /* | |
36 | * Turn off coherency | |
37 | */ | |
38 | " mrc p15, 0, %0, c1, c0, 1\n" | |
ad849a22 | 39 | " bic %0, %0, %3\n" |
11adcc29 CY |
40 | " mcr p15, 0, %0, c1, c0, 1\n" |
41 | " mrc p15, 0, %0, c1, c0, 0\n" | |
30b99d07 | 42 | " bic %0, %0, %2\n" |
11adcc29 CY |
43 | " mcr p15, 0, %0, c1, c0, 0\n" |
44 | : "=&r" (v) | |
ad849a22 | 45 | : "r" (0), "Ir" (CR_C), "Ir" (0x40) |
11adcc29 CY |
46 | : "cc"); |
47 | } | |
48 | ||
756e46db AK |
49 | static inline void cpu_enter_lowpower_a15(void) |
50 | { | |
51 | unsigned int v; | |
52 | ||
53 | asm volatile( | |
54 | " mrc p15, 0, %0, c1, c0, 0\n" | |
55 | " bic %0, %0, %1\n" | |
56 | " mcr p15, 0, %0, c1, c0, 0\n" | |
57 | : "=&r" (v) | |
58 | : "Ir" (CR_C) | |
59 | : "cc"); | |
60 | ||
61 | flush_cache_louis(); | |
62 | ||
63 | asm volatile( | |
64 | /* | |
65 | * Turn off coherency | |
66 | */ | |
67 | " mrc p15, 0, %0, c1, c0, 1\n" | |
68 | " bic %0, %0, %1\n" | |
69 | " mcr p15, 0, %0, c1, c0, 1\n" | |
70 | : "=&r" (v) | |
71 | : "Ir" (0x40) | |
72 | : "cc"); | |
73 | ||
74 | isb(); | |
75 | dsb(); | |
76 | } | |
77 | ||
11adcc29 CY |
78 | static inline void cpu_leave_lowpower(void) |
79 | { | |
80 | unsigned int v; | |
81 | ||
82 | asm volatile( | |
83 | "mrc p15, 0, %0, c1, c0, 0\n" | |
e3d9c625 | 84 | " orr %0, %0, %1\n" |
11adcc29 CY |
85 | " mcr p15, 0, %0, c1, c0, 0\n" |
86 | " mrc p15, 0, %0, c1, c0, 1\n" | |
ad849a22 | 87 | " orr %0, %0, %2\n" |
11adcc29 CY |
88 | " mcr p15, 0, %0, c1, c0, 1\n" |
89 | : "=&r" (v) | |
ad849a22 | 90 | : "Ir" (CR_C), "Ir" (0x40) |
11adcc29 CY |
91 | : "cc"); |
92 | } | |
93 | ||
d4450261 | 94 | static inline void platform_do_lowpower(unsigned int cpu, int *spurious) |
11adcc29 | 95 | { |
11adcc29 | 96 | for (;;) { |
911c29b0 JM |
97 | |
98 | /* make cpu1 to be turned off at next WFI command */ | |
99 | if (cpu == 1) | |
100 | __raw_writel(0, S5P_ARM_CORE1_CONFIGURATION); | |
101 | ||
11adcc29 CY |
102 | /* |
103 | * here's the WFI | |
104 | */ | |
105 | asm(".word 0xe320f003\n" | |
106 | : | |
107 | : | |
108 | : "memory", "cc"); | |
109 | ||
2f41c36b | 110 | if (pen_release == cpu_logical_map(cpu)) { |
11adcc29 CY |
111 | /* |
112 | * OK, proper wakeup, we're done | |
113 | */ | |
114 | break; | |
115 | } | |
116 | ||
117 | /* | |
d4450261 | 118 | * Getting here, means that we have come out of WFI without |
11adcc29 CY |
119 | * having been woken up - this shouldn't happen |
120 | * | |
d4450261 RK |
121 | * Just note it happening - when we're woken, we can report |
122 | * its occurrence. | |
11adcc29 | 123 | */ |
d4450261 | 124 | (*spurious)++; |
11adcc29 CY |
125 | } |
126 | } | |
127 | ||
11adcc29 CY |
128 | /* |
129 | * platform-specific code to shutdown a CPU | |
130 | * | |
131 | * Called with IRQs disabled | |
132 | */ | |
06853ae4 | 133 | void __ref exynos_cpu_die(unsigned int cpu) |
11adcc29 | 134 | { |
d4450261 | 135 | int spurious = 0; |
756e46db | 136 | int primary_part = 0; |
d4450261 | 137 | |
11adcc29 | 138 | /* |
756e46db AK |
139 | * we're ready for shutdown now, so do it. |
140 | * Exynos4 is A9 based while Exynos5 is A15; check the CPU part | |
141 | * number by reading the Main ID register and then perform the | |
142 | * appropriate sequence for entering low power. | |
11adcc29 | 143 | */ |
756e46db AK |
144 | asm("mrc p15, 0, %0, c0, c0, 0" : "=r"(primary_part) : : "cc"); |
145 | if ((primary_part & 0xfff0) == 0xc0f0) | |
146 | cpu_enter_lowpower_a15(); | |
147 | else | |
148 | cpu_enter_lowpower_a9(); | |
149 | ||
d4450261 | 150 | platform_do_lowpower(cpu, &spurious); |
11adcc29 CY |
151 | |
152 | /* | |
153 | * bring this CPU back into the world of cache | |
154 | * coherency, and then restore interrupts | |
155 | */ | |
156 | cpu_leave_lowpower(); | |
d4450261 RK |
157 | |
158 | if (spurious) | |
159 | pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious); | |
11adcc29 | 160 | } |