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