pm.c (865e8b76a04d018f23d809ebf735c52105e3adb2) pm.c (712eddf70225ab5ae65e946e22d2dfe6b93e8dd1)
1/*
2 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * EXYNOS - Power Management support
6 *
7 * Based on arch/arm/mach-s3c2410/pm.c
8 * Copyright (c) 2006 Simtec Electronics

--- 165 unchanged lines hidden (view full) ---

174 if (call_firmware_op(resume) == -ENOSYS)
175 exynos_cpu_restore_register();
176 }
177
178 exynos_pm_central_resume();
179
180 cpu_pm_exit();
181}
1/*
2 * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
3 * http://www.samsung.com
4 *
5 * EXYNOS - Power Management support
6 *
7 * Based on arch/arm/mach-s3c2410/pm.c
8 * Copyright (c) 2006 Simtec Electronics

--- 165 unchanged lines hidden (view full) ---

174 if (call_firmware_op(resume) == -ENOSYS)
175 exynos_cpu_restore_register();
176 }
177
178 exynos_pm_central_resume();
179
180 cpu_pm_exit();
181}
182
183static atomic_t cpu1_wakeup = ATOMIC_INIT(0);
184
185static int exynos_cpu0_enter_aftr(void)
186{
187 int ret = -1;
188
189 /*
190 * If the other cpu is powered on, we have to power it off, because
191 * the AFTR state won't work otherwise
192 */
193 if (cpu_online(1)) {
194 /*
195 * We reach a sync point with the coupled idle state, we know
196 * the other cpu will power down itself or will abort the
197 * sequence, let's wait for one of these to happen
198 */
199 while (exynos_cpu_power_state(1)) {
200 /*
201 * The other cpu may skip idle and boot back
202 * up again
203 */
204 if (atomic_read(&cpu1_wakeup))
205 goto abort;
206
207 /*
208 * The other cpu may bounce through idle and
209 * boot back up again, getting stuck in the
210 * boot rom code
211 */
212 if (__raw_readl(cpu_boot_reg_base()) == 0)
213 goto abort;
214
215 cpu_relax();
216 }
217 }
218
219 exynos_enter_aftr();
220 ret = 0;
221
222abort:
223 if (cpu_online(1)) {
224 /*
225 * Set the boot vector to something non-zero
226 */
227 __raw_writel(virt_to_phys(exynos_cpu_resume),
228 cpu_boot_reg_base());
229 dsb();
230
231 /*
232 * Turn on cpu1 and wait for it to be on
233 */
234 exynos_cpu_power_up(1);
235 while (exynos_cpu_power_state(1) != S5P_CORE_LOCAL_PWR_EN)
236 cpu_relax();
237
238 while (!atomic_read(&cpu1_wakeup)) {
239 /*
240 * Poke cpu1 out of the boot rom
241 */
242 __raw_writel(virt_to_phys(exynos_cpu_resume),
243 cpu_boot_reg_base());
244
245 arch_send_wakeup_ipi_mask(cpumask_of(1));
246 }
247 }
248
249 return ret;
250}
251
252static int exynos_wfi_finisher(unsigned long flags)
253{
254 cpu_do_idle();
255
256 return -1;
257}
258
259static int exynos_cpu1_powerdown(void)
260{
261 int ret = -1;
262
263 /*
264 * Idle sequence for cpu1
265 */
266 if (cpu_pm_enter())
267 goto cpu1_aborted;
268
269 /*
270 * Turn off cpu 1
271 */
272 exynos_cpu_power_down(1);
273
274 ret = cpu_suspend(0, exynos_wfi_finisher);
275
276 cpu_pm_exit();
277
278cpu1_aborted:
279 dsb();
280 /*
281 * Notify cpu 0 that cpu 1 is awake
282 */
283 atomic_set(&cpu1_wakeup, 1);
284
285 return ret;
286}
287
288static void exynos_pre_enter_aftr(void)
289{
290 __raw_writel(virt_to_phys(exynos_cpu_resume), cpu_boot_reg_base());
291}
292
293static void exynos_post_enter_aftr(void)
294{
295 atomic_set(&cpu1_wakeup, 0);
296}
297
298struct cpuidle_exynos_data cpuidle_coupled_exynos_data = {
299 .cpu0_enter_aftr = exynos_cpu0_enter_aftr,
300 .cpu1_powerdown = exynos_cpu1_powerdown,
301 .pre_enter_aftr = exynos_pre_enter_aftr,
302 .post_enter_aftr = exynos_post_enter_aftr,
303};