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>
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>
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
28 atomic_t hotplug_cpu_count
= ATOMIC_INIT(1);
32 #ifndef CONFIG_MTK_IN_HOUSE_TEE_SUPPORT
36 static inline void cpu_enter_lowpower(unsigned int cpu
)
38 //HOTPLUG_INFO("cpu_enter_lowpower\n");
41 spm_hot_plug_out_after(cpu
);
44 /* Clear the SCTLR C bit to prevent further data cache allocation */
47 /* Clean and invalidate all data from the L1 data cache */
48 inner_dcache_flush_L1();
49 //Just flush the cache.
52 /* Clean all data from the L2 data cache */
53 __inner_clean_dcache_L2();
55 /* Execute a CLREX instruction */
56 __asm__
__volatile__("clrex");
58 /* Switch the processor from SMP mode to AMP mode by clearing the ACTLR SMP bit */
62 static inline void cpu_leave_lowpower(unsigned int cpu
)
64 //HOTPLUG_INFO("cpu_leave_lowpower\n");
66 /* Set the ACTLR.SMP bit to 1 for SMP mode */
73 static inline void platform_do_lowpower(unsigned int cpu
, int *spurious
)
75 /* Just enter wfi for now. TODO: Properly shut off the cpu. */
78 /* Execute an ISB instruction to ensure that all of the CP15 register changes from the previous steps have been committed */
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 */
87 __asm__
__volatile__("wfi");
89 if (pen_release
== cpu
) {
91 * OK, proper wakeup, we're done
97 * Getting here, means that we have come out of WFI without
98 * having been woken up - this shouldn't happen
100 * Just note it happening - when we're woken, we can report
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
)
111 /* TEE PM to do low power */
112 kree_pm_cpu_lowpower(&pen_release
, cpu
);
114 * Getting here, means that we have come out of WFI without
115 * having been woken up - this shouldn't happen
117 * Just note it happening - when we're woken, we can report
130 int platform_cpu_kill(unsigned int cpu
)
132 HOTPLUG_INFO("platform_cpu_kill, cpu: %d\n", cpu
);
134 #ifdef CONFIG_HOTPLUG_WITH_POWER_CTRL
138 spm_mtcmos_ctrl_cpu1(STA_POWER_DOWN
, 1);
141 spm_mtcmos_ctrl_cpu2(STA_POWER_DOWN
, 1);
144 spm_mtcmos_ctrl_cpu3(STA_POWER_DOWN
, 1);
150 atomic_dec(&hotplug_cpu_count
);
156 * platform_cpu_die: shutdown a CPU
159 void platform_cpu_die(unsigned int cpu
)
162 struct wd_api
*wd_api
= NULL
;
164 HOTPLUG_INFO("platform_cpu_die, cpu: %d\n", cpu
);
168 wd_api
->wd_cpu_hot_plug_off_notify(cpu
);
171 * we're ready for shutdown now, so do it
173 cpu_enter_lowpower(cpu
);
174 platform_do_lowpower(cpu
, &spurious
);
177 * bring this CPU back into the world of cache
178 * coherency, and then restore interrupts
180 cpu_leave_lowpower(cpu
);
183 HOTPLUG_INFO("platform_do_lowpower, spurious wakeup call, cpu: %d, spurious: %d\n", cpu
, spurious
);
187 * platform_cpu_disable:
191 int platform_cpu_disable(unsigned int cpu
)
194 * we don't allow CPU 0 to be shutdown (it is still too special
195 * e.g. clock tick interrupts)
197 HOTPLUG_INFO("platform_cpu_disable, cpu: %d\n", cpu
);
198 return cpu
== 0 ? -EPERM
: 0;