Merge tag 'v3.10.55' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / arch / arm / mach-mt8127 / hotplug.c
1 #include <linux/errno.h> //EPERM
2 #include <asm/cacheflush.h> //flush_cache_all
3 #include <mach/hotplug.h>
4 #ifdef CONFIG_HOTPLUG_WITH_POWER_CTRL
5 #include <mach/mt_spm_mtcmos.h>
6 #endif
7 #include <mach/mt_spm_idle.h>
8 #include <mach/wd_api.h>
9 #ifdef CONFIG_MTK_IN_HOUSE_TEE_SUPPORT
10 #include <trustzone/kree/tz_pm.h>
11 #endif
12
13 /*
14 * extern function
15 */
16 extern void __disable_dcache(void); //definition in mt_cache_v7.S
17 extern void __enable_dcache(void); //definition in mt_cache_v7.S
18 extern void __inner_clean_dcache_L2(void); //definition in mt_cache_v7.S
19 extern void inner_dcache_flush_L1(void); //definition in inner_cache.c
20 extern void __switch_to_smp(void); //definition in mt_hotplug.S
21 extern void __switch_to_amp(void); //definition in mt_hotplug.S
22
23
24
25 /*
26 * global variable
27 */
28 atomic_t hotplug_cpu_count = ATOMIC_INIT(1);
29
30
31
32 #ifndef CONFIG_MTK_IN_HOUSE_TEE_SUPPORT
33 /*
34 * static function
35 */
36 static inline void cpu_enter_lowpower(unsigned int cpu)
37 {
38 //HOTPLUG_INFO("cpu_enter_lowpower\n");
39
40 #ifdef SPM_MCDI_FUNC
41 spm_hot_plug_out_after(cpu);
42 #endif
43
44 /* Clear the SCTLR C bit to prevent further data cache allocation */
45 __disable_dcache();
46
47 /* Clean and invalidate all data from the L1 data cache */
48 inner_dcache_flush_L1();
49 //Just flush the cache.
50 //flush_cache_all();
51
52 /* Clean all data from the L2 data cache */
53 __inner_clean_dcache_L2();
54
55 /* Execute a CLREX instruction */
56 __asm__ __volatile__("clrex");
57
58 /* Switch the processor from SMP mode to AMP mode by clearing the ACTLR SMP bit */
59 __switch_to_amp();
60 }
61
62 static inline void cpu_leave_lowpower(unsigned int cpu)
63 {
64 //HOTPLUG_INFO("cpu_leave_lowpower\n");
65
66 /* Set the ACTLR.SMP bit to 1 for SMP mode */
67 __switch_to_smp();
68
69 /* Enable dcache */
70 __enable_dcache();
71 }
72
73 static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
74 {
75 /* Just enter wfi for now. TODO: Properly shut off the cpu. */
76 for (;;) {
77
78 /* Execute an ISB instruction to ensure that all of the CP15 register changes from the previous steps have been committed */
79 isb();
80
81 /* Execute a DSB instruction to ensure that all cache, TLB and branch predictor maintenance operations issued by any processor in the multiprocessor device before the SMP bit was cleared have completed */
82 dsb();
83
84 /*
85 * here's the WFI
86 */
87 __asm__ __volatile__("wfi");
88
89 if (pen_release == cpu) {
90 /*
91 * OK, proper wakeup, we're done
92 */
93 break;
94 }
95
96 /*
97 * Getting here, means that we have come out of WFI without
98 * having been woken up - this shouldn't happen
99 *
100 * Just note it happening - when we're woken, we can report
101 * its occurrence.
102 */
103 (*spurious)++;
104 }
105 }
106 #else // defined(CONFIG_MTK_IN_HOUSE_TEE_SUPPORT)
107 static inline void cpu_enter_lowpower(unsigned int cpu) { return; }
108 static inline void cpu_leave_lowpower(unsigned int cpu) { return; }
109 static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
110 {
111 /* TEE PM to do low power */
112 kree_pm_cpu_lowpower(&pen_release, cpu);
113 /*
114 * Getting here, means that we have come out of WFI without
115 * having been woken up - this shouldn't happen
116 *
117 * Just note it happening - when we're woken, we can report
118 * its occurrence.
119 */
120 (*spurious)++;
121 }
122 #endif
123
124
125 /*
126 * platform_cpu_kill:
127 * @cpu:
128 * Return TBD.
129 */
130 int platform_cpu_kill(unsigned int cpu)
131 {
132 HOTPLUG_INFO("platform_cpu_kill, cpu: %d\n", cpu);
133
134 #ifdef CONFIG_HOTPLUG_WITH_POWER_CTRL
135 switch(cpu)
136 {
137 case 1:
138 spm_mtcmos_ctrl_cpu1(STA_POWER_DOWN, 1);
139 break;
140 case 2:
141 spm_mtcmos_ctrl_cpu2(STA_POWER_DOWN, 1);
142 break;
143 case 3:
144 spm_mtcmos_ctrl_cpu3(STA_POWER_DOWN, 1);
145 break;
146 default:
147 break;
148 }
149 #endif
150 atomic_dec(&hotplug_cpu_count);
151
152 return 1;
153 }
154
155 /*
156 * platform_cpu_die: shutdown a CPU
157 * @cpu:
158 */
159 void platform_cpu_die(unsigned int cpu)
160 {
161 int spurious = 0;
162 struct wd_api *wd_api = NULL;
163
164 HOTPLUG_INFO("platform_cpu_die, cpu: %d\n", cpu);
165
166 get_wd_api(&wd_api);
167 if (wd_api)
168 wd_api->wd_cpu_hot_plug_off_notify(cpu);
169
170 /*
171 * we're ready for shutdown now, so do it
172 */
173 cpu_enter_lowpower(cpu);
174 platform_do_lowpower(cpu, &spurious);
175
176 /*
177 * bring this CPU back into the world of cache
178 * coherency, and then restore interrupts
179 */
180 cpu_leave_lowpower(cpu);
181
182 if (spurious)
183 HOTPLUG_INFO("platform_do_lowpower, spurious wakeup call, cpu: %d, spurious: %d\n", cpu, spurious);
184 }
185
186 /*
187 * platform_cpu_disable:
188 * @cpu:
189 * Return error code.
190 */
191 int platform_cpu_disable(unsigned int cpu)
192 {
193 /*
194 * we don't allow CPU 0 to be shutdown (it is still too special
195 * e.g. clock tick interrupts)
196 */
197 HOTPLUG_INFO("platform_cpu_disable, cpu: %d\n", cpu);
198 return cpu == 0 ? -EPERM : 0;
199 }