pm.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*
  2. * CPU complex suspend & resume functions for Tegra SoCs
  3. *
  4. * Copyright (c) 2009-2012, NVIDIA Corporation. All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms and conditions of the GNU General Public License,
  8. * version 2, as published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <linux/kernel.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/io.h>
  21. #include <linux/cpumask.h>
  22. #include <linux/delay.h>
  23. #include <linux/cpu_pm.h>
  24. #include <linux/suspend.h>
  25. #include <linux/err.h>
  26. #include <linux/clk/tegra.h>
  27. #include <asm/smp_plat.h>
  28. #include <asm/cacheflush.h>
  29. #include <asm/suspend.h>
  30. #include <asm/idmap.h>
  31. #include <asm/proc-fns.h>
  32. #include <asm/tlbflush.h>
  33. #include "iomap.h"
  34. #include "reset.h"
  35. #include "flowctrl.h"
  36. #include "fuse.h"
  37. #include "pmc.h"
  38. #include "sleep.h"
  39. #ifdef CONFIG_PM_SLEEP
  40. static DEFINE_SPINLOCK(tegra_lp2_lock);
  41. void (*tegra_tear_down_cpu)(void);
  42. static void tegra_tear_down_cpu_init(void)
  43. {
  44. switch (tegra_chip_id) {
  45. case TEGRA20:
  46. if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC))
  47. tegra_tear_down_cpu = tegra20_tear_down_cpu;
  48. break;
  49. case TEGRA30:
  50. if (IS_ENABLED(CONFIG_ARCH_TEGRA_3x_SOC))
  51. tegra_tear_down_cpu = tegra30_tear_down_cpu;
  52. break;
  53. }
  54. }
  55. /*
  56. * restore_cpu_complex
  57. *
  58. * restores cpu clock setting, clears flow controller
  59. *
  60. * Always called on CPU 0.
  61. */
  62. static void restore_cpu_complex(void)
  63. {
  64. int cpu = smp_processor_id();
  65. BUG_ON(cpu != 0);
  66. #ifdef CONFIG_SMP
  67. cpu = cpu_logical_map(cpu);
  68. #endif
  69. /* Restore the CPU clock settings */
  70. tegra_cpu_clock_resume();
  71. flowctrl_cpu_suspend_exit(cpu);
  72. }
  73. /*
  74. * suspend_cpu_complex
  75. *
  76. * saves pll state for use by restart_plls, prepares flow controller for
  77. * transition to suspend state
  78. *
  79. * Must always be called on cpu 0.
  80. */
  81. static void suspend_cpu_complex(void)
  82. {
  83. int cpu = smp_processor_id();
  84. BUG_ON(cpu != 0);
  85. #ifdef CONFIG_SMP
  86. cpu = cpu_logical_map(cpu);
  87. #endif
  88. /* Save the CPU clock settings */
  89. tegra_cpu_clock_suspend();
  90. flowctrl_cpu_suspend_enter(cpu);
  91. }
  92. void tegra_clear_cpu_in_lp2(void)
  93. {
  94. int phy_cpu_id = cpu_logical_map(smp_processor_id());
  95. u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
  96. spin_lock(&tegra_lp2_lock);
  97. BUG_ON(!(*cpu_in_lp2 & BIT(phy_cpu_id)));
  98. *cpu_in_lp2 &= ~BIT(phy_cpu_id);
  99. spin_unlock(&tegra_lp2_lock);
  100. }
  101. bool tegra_set_cpu_in_lp2(void)
  102. {
  103. int phy_cpu_id = cpu_logical_map(smp_processor_id());
  104. bool last_cpu = false;
  105. cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
  106. u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
  107. spin_lock(&tegra_lp2_lock);
  108. BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
  109. *cpu_in_lp2 |= BIT(phy_cpu_id);
  110. if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
  111. last_cpu = true;
  112. else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1)
  113. tegra20_cpu_set_resettable_soon();
  114. spin_unlock(&tegra_lp2_lock);
  115. return last_cpu;
  116. }
  117. int tegra_cpu_do_idle(void)
  118. {
  119. return cpu_do_idle();
  120. }
  121. static int tegra_sleep_cpu(unsigned long v2p)
  122. {
  123. setup_mm_for_reboot();
  124. tegra_sleep_cpu_finish(v2p);
  125. /* should never here */
  126. BUG();
  127. return 0;
  128. }
  129. void tegra_idle_lp2_last(void)
  130. {
  131. tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);
  132. cpu_cluster_pm_enter();
  133. suspend_cpu_complex();
  134. cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
  135. restore_cpu_complex();
  136. cpu_cluster_pm_exit();
  137. }
  138. enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
  139. enum tegra_suspend_mode mode)
  140. {
  141. /* Tegra114 didn't support any suspending mode yet. */
  142. if (tegra_chip_id == TEGRA114)
  143. return TEGRA_SUSPEND_NONE;
  144. /*
  145. * The Tegra devices only support suspending to LP2 currently.
  146. */
  147. if (mode > TEGRA_SUSPEND_LP2)
  148. return TEGRA_SUSPEND_LP2;
  149. return mode;
  150. }
  151. static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
  152. [TEGRA_SUSPEND_NONE] = "none",
  153. [TEGRA_SUSPEND_LP2] = "LP2",
  154. [TEGRA_SUSPEND_LP1] = "LP1",
  155. [TEGRA_SUSPEND_LP0] = "LP0",
  156. };
  157. static int tegra_suspend_enter(suspend_state_t state)
  158. {
  159. enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
  160. if (WARN_ON(mode < TEGRA_SUSPEND_NONE ||
  161. mode >= TEGRA_MAX_SUSPEND_MODE))
  162. return -EINVAL;
  163. pr_info("Entering suspend state %s\n", lp_state[mode]);
  164. tegra_pmc_pm_set(mode);
  165. local_fiq_disable();
  166. suspend_cpu_complex();
  167. switch (mode) {
  168. case TEGRA_SUSPEND_LP2:
  169. tegra_set_cpu_in_lp2();
  170. break;
  171. default:
  172. break;
  173. }
  174. cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
  175. switch (mode) {
  176. case TEGRA_SUSPEND_LP2:
  177. tegra_clear_cpu_in_lp2();
  178. break;
  179. default:
  180. break;
  181. }
  182. restore_cpu_complex();
  183. local_fiq_enable();
  184. return 0;
  185. }
  186. static const struct platform_suspend_ops tegra_suspend_ops = {
  187. .valid = suspend_valid_only_mem,
  188. .enter = tegra_suspend_enter,
  189. };
  190. void __init tegra_init_suspend(void)
  191. {
  192. if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
  193. return;
  194. tegra_tear_down_cpu_init();
  195. tegra_pmc_suspend_init();
  196. suspend_set_ops(&tegra_suspend_ops);
  197. }
  198. #endif