pm.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. /*
  43. * restore_cpu_complex
  44. *
  45. * restores cpu clock setting, clears flow controller
  46. *
  47. * Always called on CPU 0.
  48. */
  49. static void restore_cpu_complex(void)
  50. {
  51. int cpu = smp_processor_id();
  52. BUG_ON(cpu != 0);
  53. #ifdef CONFIG_SMP
  54. cpu = cpu_logical_map(cpu);
  55. #endif
  56. /* Restore the CPU clock settings */
  57. tegra_cpu_clock_resume();
  58. flowctrl_cpu_suspend_exit(cpu);
  59. }
  60. /*
  61. * suspend_cpu_complex
  62. *
  63. * saves pll state for use by restart_plls, prepares flow controller for
  64. * transition to suspend state
  65. *
  66. * Must always be called on cpu 0.
  67. */
  68. static void suspend_cpu_complex(void)
  69. {
  70. int cpu = smp_processor_id();
  71. BUG_ON(cpu != 0);
  72. #ifdef CONFIG_SMP
  73. cpu = cpu_logical_map(cpu);
  74. #endif
  75. /* Save the CPU clock settings */
  76. tegra_cpu_clock_suspend();
  77. flowctrl_cpu_suspend_enter(cpu);
  78. }
  79. void tegra_clear_cpu_in_lp2(int phy_cpu_id)
  80. {
  81. u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
  82. spin_lock(&tegra_lp2_lock);
  83. BUG_ON(!(*cpu_in_lp2 & BIT(phy_cpu_id)));
  84. *cpu_in_lp2 &= ~BIT(phy_cpu_id);
  85. spin_unlock(&tegra_lp2_lock);
  86. }
  87. bool tegra_set_cpu_in_lp2(int phy_cpu_id)
  88. {
  89. bool last_cpu = false;
  90. cpumask_t *cpu_lp2_mask = tegra_cpu_lp2_mask;
  91. u32 *cpu_in_lp2 = tegra_cpu_lp2_mask;
  92. spin_lock(&tegra_lp2_lock);
  93. BUG_ON((*cpu_in_lp2 & BIT(phy_cpu_id)));
  94. *cpu_in_lp2 |= BIT(phy_cpu_id);
  95. if ((phy_cpu_id == 0) && cpumask_equal(cpu_lp2_mask, cpu_online_mask))
  96. last_cpu = true;
  97. else if (tegra_chip_id == TEGRA20 && phy_cpu_id == 1)
  98. tegra20_cpu_set_resettable_soon();
  99. spin_unlock(&tegra_lp2_lock);
  100. return last_cpu;
  101. }
  102. int tegra_cpu_do_idle(void)
  103. {
  104. return cpu_do_idle();
  105. }
  106. static int tegra_sleep_cpu(unsigned long v2p)
  107. {
  108. setup_mm_for_reboot();
  109. tegra_sleep_cpu_finish(v2p);
  110. /* should never here */
  111. BUG();
  112. return 0;
  113. }
  114. void tegra_idle_lp2_last(void)
  115. {
  116. tegra_pmc_pm_set(TEGRA_SUSPEND_LP2);
  117. cpu_cluster_pm_enter();
  118. suspend_cpu_complex();
  119. cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
  120. restore_cpu_complex();
  121. cpu_cluster_pm_exit();
  122. }
  123. enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
  124. enum tegra_suspend_mode mode)
  125. {
  126. /* Tegra114 didn't support any suspending mode yet. */
  127. if (tegra_chip_id == TEGRA114)
  128. return TEGRA_SUSPEND_NONE;
  129. /*
  130. * The Tegra devices only support suspending to LP2 currently.
  131. */
  132. if (mode > TEGRA_SUSPEND_LP2)
  133. return TEGRA_SUSPEND_LP2;
  134. return mode;
  135. }
  136. static const char *lp_state[TEGRA_MAX_SUSPEND_MODE] = {
  137. [TEGRA_SUSPEND_NONE] = "none",
  138. [TEGRA_SUSPEND_LP2] = "LP2",
  139. [TEGRA_SUSPEND_LP1] = "LP1",
  140. [TEGRA_SUSPEND_LP0] = "LP0",
  141. };
  142. static int __cpuinit tegra_suspend_enter(suspend_state_t state)
  143. {
  144. enum tegra_suspend_mode mode = tegra_pmc_get_suspend_mode();
  145. if (WARN_ON(mode < TEGRA_SUSPEND_NONE ||
  146. mode >= TEGRA_MAX_SUSPEND_MODE))
  147. return -EINVAL;
  148. pr_info("Entering suspend state %s\n", lp_state[mode]);
  149. tegra_pmc_pm_set(mode);
  150. local_fiq_disable();
  151. suspend_cpu_complex();
  152. switch (mode) {
  153. case TEGRA_SUSPEND_LP2:
  154. tegra_set_cpu_in_lp2(0);
  155. break;
  156. default:
  157. break;
  158. }
  159. cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
  160. switch (mode) {
  161. case TEGRA_SUSPEND_LP2:
  162. tegra_clear_cpu_in_lp2(0);
  163. break;
  164. default:
  165. break;
  166. }
  167. restore_cpu_complex();
  168. local_fiq_enable();
  169. return 0;
  170. }
  171. static const struct platform_suspend_ops tegra_suspend_ops = {
  172. .valid = suspend_valid_only_mem,
  173. .enter = tegra_suspend_enter,
  174. };
  175. void __init tegra_init_suspend(void)
  176. {
  177. if (tegra_pmc_get_suspend_mode() == TEGRA_SUSPEND_NONE)
  178. return;
  179. tegra_pmc_suspend_init();
  180. suspend_set_ops(&tegra_suspend_ops);
  181. }
  182. #endif