Merge branch 'l2x0-pull-rmk' of git://dev.omapzoom.org/pub/scm/santosh/kernel-omap4...
[pandora-kernel.git] / arch / arm / mach-s5pv310 / hotplug.c
1 /* linux arch/arm/mach-s5pv310/hotplug.c
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>
16 #include <linux/completion.h>
17
18 #include <asm/cacheflush.h>
19
20 extern volatile int pen_release;
21
22 static DECLARE_COMPLETION(cpu_killed);
23
24 static inline void cpu_enter_lowpower(void)
25 {
26         unsigned int v;
27
28         flush_cache_all();
29         asm volatile(
30         "       mcr     p15, 0, %1, c7, c5, 0\n"
31         "       mcr     p15, 0, %1, c7, c10, 4\n"
32         /*
33          * Turn off coherency
34          */
35         "       mrc     p15, 0, %0, c1, c0, 1\n"
36         "       bic     %0, %0, #0x20\n"
37         "       mcr     p15, 0, %0, c1, c0, 1\n"
38         "       mrc     p15, 0, %0, c1, c0, 0\n"
39         "       bic     %0, %0, #0x04\n"
40         "       mcr     p15, 0, %0, c1, c0, 0\n"
41           : "=&r" (v)
42           : "r" (0)
43           : "cc");
44 }
45
46 static inline void cpu_leave_lowpower(void)
47 {
48         unsigned int v;
49
50         asm volatile(
51         "mrc    p15, 0, %0, c1, c0, 0\n"
52         "       orr     %0, %0, #0x04\n"
53         "       mcr     p15, 0, %0, c1, c0, 0\n"
54         "       mrc     p15, 0, %0, c1, c0, 1\n"
55         "       orr     %0, %0, #0x20\n"
56         "       mcr     p15, 0, %0, c1, c0, 1\n"
57           : "=&r" (v)
58           :
59           : "cc");
60 }
61
62 static inline void platform_do_lowpower(unsigned int cpu)
63 {
64         /*
65          * there is no power-control hardware on this platform, so all
66          * we can do is put the core into WFI; this is safe as the calling
67          * code will have already disabled interrupts
68          */
69         for (;;) {
70                 /*
71                  * here's the WFI
72                  */
73                 asm(".word      0xe320f003\n"
74                     :
75                     :
76                     : "memory", "cc");
77
78                 if (pen_release == cpu) {
79                         /*
80                          * OK, proper wakeup, we're done
81                          */
82                         break;
83                 }
84
85                 /*
86                  * getting here, means that we have come out of WFI without
87                  * having been woken up - this shouldn't happen
88                  *
89                  * The trouble is, letting people know about this is not really
90                  * possible, since we are currently running incoherently, and
91                  * therefore cannot safely call printk() or anything else
92                  */
93 #ifdef DEBUG
94                 printk(KERN_WARN "CPU%u: spurious wakeup call\n", cpu);
95 #endif
96         }
97 }
98
99 int platform_cpu_kill(unsigned int cpu)
100 {
101         return wait_for_completion_timeout(&cpu_killed, 5000);
102 }
103
104 /*
105  * platform-specific code to shutdown a CPU
106  *
107  * Called with IRQs disabled
108  */
109 void platform_cpu_die(unsigned int cpu)
110 {
111 #ifdef DEBUG
112         unsigned int this_cpu = hard_smp_processor_id();
113
114         if (cpu != this_cpu) {
115                 printk(KERN_CRIT "Eek! platform_cpu_die running on %u, should be %u\n",
116                            this_cpu, cpu);
117                 BUG();
118         }
119 #endif
120
121         printk(KERN_NOTICE "CPU%u: shutdown\n", cpu);
122         complete(&cpu_killed);
123
124         /*
125          * we're ready for shutdown now, so do it
126          */
127         cpu_enter_lowpower();
128         platform_do_lowpower(cpu);
129
130         /*
131          * bring this CPU back into the world of cache
132          * coherency, and then restore interrupts
133          */
134         cpu_leave_lowpower();
135 }
136
137 int platform_cpu_disable(unsigned int cpu)
138 {
139         /*
140          * we don't allow CPU 0 to be shutdown (it is still too special
141          * e.g. clock tick interrupts)
142          */
143         return cpu == 0 ? -EPERM : 0;
144 }