]> Pileus Git - ~andy/linux/blob - arch/arm/mach-spear13xx/hotplug.c
Merge branch 'for-3.5-take-2' of git://linux-nfs.org/~bfields/linux
[~andy/linux] / arch / arm / mach-spear13xx / hotplug.c
1 /*
2  * linux/arch/arm/mach-spear13xx/hotplug.c
3  *
4  * Copyright (C) 2012 ST Microelectronics Ltd.
5  * Deepak Sikri <deepak.sikri@st.com>
6  *
7  * based upon linux/arch/arm/mach-realview/hotplug.c
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/smp.h>
16 #include <asm/cacheflush.h>
17 #include <asm/cp15.h>
18 #include <asm/smp_plat.h>
19
20 extern volatile int pen_release;
21
22 static inline void cpu_enter_lowpower(void)
23 {
24         unsigned int v;
25
26         flush_cache_all();
27         asm volatile(
28         "       mcr     p15, 0, %1, c7, c5, 0\n"
29         "       dsb\n"
30         /*
31          * Turn off coherency
32          */
33         "       mrc     p15, 0, %0, c1, c0, 1\n"
34         "       bic     %0, %0, #0x20\n"
35         "       mcr     p15, 0, %0, c1, c0, 1\n"
36         "       mrc     p15, 0, %0, c1, c0, 0\n"
37         "       bic     %0, %0, %2\n"
38         "       mcr     p15, 0, %0, c1, c0, 0\n"
39         : "=&r" (v)
40         : "r" (0), "Ir" (CR_C)
41         : "cc", "memory");
42 }
43
44 static inline void cpu_leave_lowpower(void)
45 {
46         unsigned int v;
47
48         asm volatile("mrc       p15, 0, %0, c1, c0, 0\n"
49         "       orr     %0, %0, %1\n"
50         "       mcr     p15, 0, %0, c1, c0, 0\n"
51         "       mrc     p15, 0, %0, c1, c0, 1\n"
52         "       orr     %0, %0, #0x20\n"
53         "       mcr     p15, 0, %0, c1, c0, 1\n"
54         : "=&r" (v)
55         : "Ir" (CR_C)
56         : "cc");
57 }
58
59 static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
60 {
61         for (;;) {
62                 wfi();
63
64                 if (pen_release == cpu) {
65                         /*
66                          * OK, proper wakeup, we're done
67                          */
68                         break;
69                 }
70
71                 /*
72                  * Getting here, means that we have come out of WFI without
73                  * having been woken up - this shouldn't happen
74                  *
75                  * Just note it happening - when we're woken, we can report
76                  * its occurrence.
77                  */
78                 (*spurious)++;
79         }
80 }
81
82 int platform_cpu_kill(unsigned int cpu)
83 {
84         return 1;
85 }
86
87 /*
88  * platform-specific code to shutdown a CPU
89  *
90  * Called with IRQs disabled
91  */
92 void __cpuinit platform_cpu_die(unsigned int cpu)
93 {
94         int spurious = 0;
95
96         /*
97          * we're ready for shutdown now, so do it
98          */
99         cpu_enter_lowpower();
100         platform_do_lowpower(cpu, &spurious);
101
102         /*
103          * bring this CPU back into the world of cache
104          * coherency, and then restore interrupts
105          */
106         cpu_leave_lowpower();
107
108         if (spurious)
109                 pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
110 }
111
112 int platform_cpu_disable(unsigned int cpu)
113 {
114         /*
115          * we don't allow CPU 0 to be shutdown (it is still too special
116          * e.g. clock tick interrupts)
117          */
118         return cpu == 0 ? -EPERM : 0;
119 }