pm.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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
  9. * Ben Dooks <ben@simtec.co.uk>
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License version 2 as
  13. * published by the Free Software Foundation.
  14. */
  15. #include <linux/init.h>
  16. #include <linux/suspend.h>
  17. #include <linux/cpu_pm.h>
  18. #include <linux/io.h>
  19. #include <linux/err.h>
  20. #include <asm/firmware.h>
  21. #include <asm/smp_scu.h>
  22. #include <asm/suspend.h>
  23. #include <asm/cacheflush.h>
  24. #include <mach/map.h>
  25. #include <plat/pm-common.h>
  26. #include "common.h"
  27. #include "exynos-pmu.h"
  28. #include "regs-pmu.h"
  29. static inline void __iomem *exynos_boot_vector_addr(void)
  30. {
  31. if (samsung_rev() == EXYNOS4210_REV_1_1)
  32. return pmu_base_addr + S5P_INFORM7;
  33. else if (samsung_rev() == EXYNOS4210_REV_1_0)
  34. return sysram_base_addr + 0x24;
  35. return pmu_base_addr + S5P_INFORM0;
  36. }
  37. static inline void __iomem *exynos_boot_vector_flag(void)
  38. {
  39. if (samsung_rev() == EXYNOS4210_REV_1_1)
  40. return pmu_base_addr + S5P_INFORM6;
  41. else if (samsung_rev() == EXYNOS4210_REV_1_0)
  42. return sysram_base_addr + 0x20;
  43. return pmu_base_addr + S5P_INFORM1;
  44. }
  45. #define S5P_CHECK_AFTR 0xFCBA0D10
  46. /* For Cortex-A9 Diagnostic and Power control register */
  47. static unsigned int save_arm_register[2];
  48. void exynos_cpu_save_register(void)
  49. {
  50. unsigned long tmp;
  51. /* Save Power control register */
  52. asm ("mrc p15, 0, %0, c15, c0, 0"
  53. : "=r" (tmp) : : "cc");
  54. save_arm_register[0] = tmp;
  55. /* Save Diagnostic register */
  56. asm ("mrc p15, 0, %0, c15, c0, 1"
  57. : "=r" (tmp) : : "cc");
  58. save_arm_register[1] = tmp;
  59. }
  60. void exynos_cpu_restore_register(void)
  61. {
  62. unsigned long tmp;
  63. /* Restore Power control register */
  64. tmp = save_arm_register[0];
  65. asm volatile ("mcr p15, 0, %0, c15, c0, 0"
  66. : : "r" (tmp)
  67. : "cc");
  68. /* Restore Diagnostic register */
  69. tmp = save_arm_register[1];
  70. asm volatile ("mcr p15, 0, %0, c15, c0, 1"
  71. : : "r" (tmp)
  72. : "cc");
  73. }
  74. void exynos_pm_central_suspend(void)
  75. {
  76. unsigned long tmp;
  77. /* Setting Central Sequence Register for power down mode */
  78. tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
  79. tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
  80. pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
  81. }
  82. int exynos_pm_central_resume(void)
  83. {
  84. unsigned long tmp;
  85. /*
  86. * If PMU failed while entering sleep mode, WFI will be
  87. * ignored by PMU and then exiting cpu_do_idle().
  88. * S5P_CENTRAL_LOWPWR_CFG bit will not be set automatically
  89. * in this situation.
  90. */
  91. tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
  92. if (!(tmp & S5P_CENTRAL_LOWPWR_CFG)) {
  93. tmp |= S5P_CENTRAL_LOWPWR_CFG;
  94. pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
  95. /* clear the wakeup state register */
  96. pmu_raw_writel(0x0, S5P_WAKEUP_STAT);
  97. /* No need to perform below restore code */
  98. return -1;
  99. }
  100. return 0;
  101. }
  102. /* Ext-GIC nIRQ/nFIQ is the only wakeup source in AFTR */
  103. static void exynos_set_wakeupmask(long mask)
  104. {
  105. pmu_raw_writel(mask, S5P_WAKEUP_MASK);
  106. if (soc_is_exynos3250())
  107. pmu_raw_writel(0x0, S5P_WAKEUP_MASK2);
  108. }
  109. static void exynos_cpu_set_boot_vector(long flags)
  110. {
  111. __raw_writel(virt_to_phys(exynos_cpu_resume),
  112. exynos_boot_vector_addr());
  113. __raw_writel(flags, exynos_boot_vector_flag());
  114. }
  115. static int exynos_aftr_finisher(unsigned long flags)
  116. {
  117. int ret;
  118. exynos_set_wakeupmask(soc_is_exynos3250() ? 0x40003ffe : 0x0000ff3e);
  119. /* Set value of power down register for aftr mode */
  120. exynos_sys_powerdown_conf(SYS_AFTR);
  121. ret = call_firmware_op(do_idle, FW_DO_IDLE_AFTR);
  122. if (ret == -ENOSYS) {
  123. if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
  124. exynos_cpu_save_register();
  125. exynos_cpu_set_boot_vector(S5P_CHECK_AFTR);
  126. cpu_do_idle();
  127. }
  128. return 1;
  129. }
  130. void exynos_enter_aftr(void)
  131. {
  132. unsigned int cpuid = smp_processor_id();
  133. cpu_pm_enter();
  134. if (soc_is_exynos3250())
  135. exynos_set_boot_flag(cpuid, C2_STATE);
  136. exynos_pm_central_suspend();
  137. if (of_machine_is_compatible("samsung,exynos4212") ||
  138. of_machine_is_compatible("samsung,exynos4412")) {
  139. /* Setting SEQ_OPTION register */
  140. pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
  141. S5P_CENTRAL_SEQ_OPTION);
  142. }
  143. cpu_suspend(0, exynos_aftr_finisher);
  144. if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
  145. scu_enable(S5P_VA_SCU);
  146. if (call_firmware_op(resume) == -ENOSYS)
  147. exynos_cpu_restore_register();
  148. }
  149. exynos_pm_central_resume();
  150. if (soc_is_exynos3250())
  151. exynos_clear_boot_flag(cpuid, C2_STATE);
  152. cpu_pm_exit();
  153. }
  154. #if defined(CONFIG_SMP) && defined(CONFIG_ARM_EXYNOS_CPUIDLE)
  155. static atomic_t cpu1_wakeup = ATOMIC_INIT(0);
  156. static int exynos_cpu0_enter_aftr(void)
  157. {
  158. int ret = -1;
  159. /*
  160. * If the other cpu is powered on, we have to power it off, because
  161. * the AFTR state won't work otherwise
  162. */
  163. if (cpu_online(1)) {
  164. /*
  165. * We reach a sync point with the coupled idle state, we know
  166. * the other cpu will power down itself or will abort the
  167. * sequence, let's wait for one of these to happen
  168. */
  169. while (exynos_cpu_power_state(1)) {
  170. unsigned long boot_addr;
  171. /*
  172. * The other cpu may skip idle and boot back
  173. * up again
  174. */
  175. if (atomic_read(&cpu1_wakeup))
  176. goto abort;
  177. /*
  178. * The other cpu may bounce through idle and
  179. * boot back up again, getting stuck in the
  180. * boot rom code
  181. */
  182. ret = exynos_get_boot_addr(1, &boot_addr);
  183. if (ret)
  184. goto fail;
  185. ret = -1;
  186. if (boot_addr == 0)
  187. goto abort;
  188. cpu_relax();
  189. }
  190. }
  191. exynos_enter_aftr();
  192. ret = 0;
  193. abort:
  194. if (cpu_online(1)) {
  195. unsigned long boot_addr = virt_to_phys(exynos_cpu_resume);
  196. /*
  197. * Set the boot vector to something non-zero
  198. */
  199. ret = exynos_set_boot_addr(1, boot_addr);
  200. if (ret)
  201. goto fail;
  202. dsb();
  203. /*
  204. * Turn on cpu1 and wait for it to be on
  205. */
  206. exynos_cpu_power_up(1);
  207. while (exynos_cpu_power_state(1) != S5P_CORE_LOCAL_PWR_EN)
  208. cpu_relax();
  209. if (soc_is_exynos3250()) {
  210. while (!pmu_raw_readl(S5P_PMU_SPARE2) &&
  211. !atomic_read(&cpu1_wakeup))
  212. cpu_relax();
  213. if (!atomic_read(&cpu1_wakeup))
  214. exynos_core_restart(1);
  215. }
  216. while (!atomic_read(&cpu1_wakeup)) {
  217. smp_rmb();
  218. /*
  219. * Poke cpu1 out of the boot rom
  220. */
  221. ret = exynos_set_boot_addr(1, boot_addr);
  222. if (ret)
  223. goto fail;
  224. call_firmware_op(cpu_boot, 1);
  225. if (soc_is_exynos3250())
  226. dsb_sev();
  227. else
  228. arch_send_wakeup_ipi_mask(cpumask_of(1));
  229. }
  230. }
  231. fail:
  232. return ret;
  233. }
  234. static int exynos_wfi_finisher(unsigned long flags)
  235. {
  236. if (soc_is_exynos3250())
  237. flush_cache_all();
  238. cpu_do_idle();
  239. return -1;
  240. }
  241. static int exynos_cpu1_powerdown(void)
  242. {
  243. int ret = -1;
  244. /*
  245. * Idle sequence for cpu1
  246. */
  247. if (cpu_pm_enter())
  248. goto cpu1_aborted;
  249. /*
  250. * Turn off cpu 1
  251. */
  252. exynos_cpu_power_down(1);
  253. if (soc_is_exynos3250())
  254. pmu_raw_writel(0, S5P_PMU_SPARE2);
  255. ret = cpu_suspend(0, exynos_wfi_finisher);
  256. cpu_pm_exit();
  257. cpu1_aborted:
  258. dsb();
  259. /*
  260. * Notify cpu 0 that cpu 1 is awake
  261. */
  262. atomic_set(&cpu1_wakeup, 1);
  263. return ret;
  264. }
  265. static void exynos_pre_enter_aftr(void)
  266. {
  267. unsigned long boot_addr = virt_to_phys(exynos_cpu_resume);
  268. (void)exynos_set_boot_addr(1, boot_addr);
  269. }
  270. static void exynos_post_enter_aftr(void)
  271. {
  272. atomic_set(&cpu1_wakeup, 0);
  273. }
  274. struct cpuidle_exynos_data cpuidle_coupled_exynos_data = {
  275. .cpu0_enter_aftr = exynos_cpu0_enter_aftr,
  276. .cpu1_powerdown = exynos_cpu1_powerdown,
  277. .pre_enter_aftr = exynos_pre_enter_aftr,
  278. .post_enter_aftr = exynos_post_enter_aftr,
  279. };
  280. #endif /* CONFIG_SMP && CONFIG_ARM_EXYNOS_CPUIDLE */