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}; |
|