sleep-tegra20.S 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*
  2. * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
  3. * Copyright (c) 2011, Google, Inc.
  4. *
  5. * Author: Colin Cross <ccross@android.com>
  6. * Gary King <gking@nvidia.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms and conditions of the GNU General Public License,
  10. * version 2, as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <linux/linkage.h>
  21. #include <asm/assembler.h>
  22. #include <asm/proc-fns.h>
  23. #include <asm/cp15.h>
  24. #include "sleep.h"
  25. #include "flowctrl.h"
  26. #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
  27. /*
  28. * tegra20_hotplug_shutdown(void)
  29. *
  30. * puts the current cpu in reset
  31. * should never return
  32. */
  33. ENTRY(tegra20_hotplug_shutdown)
  34. /* Put this CPU down */
  35. cpu_id r0
  36. bl tegra20_cpu_shutdown
  37. mov pc, lr @ should never get here
  38. ENDPROC(tegra20_hotplug_shutdown)
  39. /*
  40. * tegra20_cpu_shutdown(int cpu)
  41. *
  42. * r0 is cpu to reset
  43. *
  44. * puts the specified CPU in wait-for-event mode on the flow controller
  45. * and puts the CPU in reset
  46. * can be called on the current cpu or another cpu
  47. * if called on the current cpu, does not return
  48. * MUST NOT BE CALLED FOR CPU 0.
  49. *
  50. * corrupts r0-r3, r12
  51. */
  52. ENTRY(tegra20_cpu_shutdown)
  53. cmp r0, #0
  54. moveq pc, lr @ must not be called for CPU 0
  55. mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
  56. mov r12, #CPU_RESETTABLE
  57. str r12, [r1]
  58. cpu_to_halt_reg r1, r0
  59. ldr r3, =TEGRA_FLOW_CTRL_VIRT
  60. mov r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
  61. str r2, [r3, r1] @ put flow controller in wait event mode
  62. ldr r2, [r3, r1]
  63. isb
  64. dsb
  65. movw r1, 0x1011
  66. mov r1, r1, lsl r0
  67. ldr r3, =TEGRA_CLK_RESET_VIRT
  68. str r1, [r3, #0x340] @ put slave CPU in reset
  69. isb
  70. dsb
  71. cpu_id r3
  72. cmp r3, r0
  73. beq .
  74. mov pc, lr
  75. ENDPROC(tegra20_cpu_shutdown)
  76. #endif
  77. #ifdef CONFIG_PM_SLEEP
  78. /*
  79. * tegra_pen_lock
  80. *
  81. * spinlock implementation with no atomic test-and-set and no coherence
  82. * using Peterson's algorithm on strongly-ordered registers
  83. * used to synchronize a cpu waking up from wfi with entering lp2 on idle
  84. *
  85. * The reference link of Peterson's algorithm:
  86. * http://en.wikipedia.org/wiki/Peterson's_algorithm
  87. *
  88. * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
  89. * on cpu 0:
  90. * r2 = flag[0] (in SCRATCH38)
  91. * r3 = flag[1] (in SCRATCH39)
  92. * on cpu1:
  93. * r2 = flag[1] (in SCRATCH39)
  94. * r3 = flag[0] (in SCRATCH38)
  95. *
  96. * must be called with MMU on
  97. * corrupts r0-r3, r12
  98. */
  99. ENTRY(tegra_pen_lock)
  100. mov32 r3, TEGRA_PMC_VIRT
  101. cpu_id r0
  102. add r1, r3, #PMC_SCRATCH37
  103. cmp r0, #0
  104. addeq r2, r3, #PMC_SCRATCH38
  105. addeq r3, r3, #PMC_SCRATCH39
  106. addne r2, r3, #PMC_SCRATCH39
  107. addne r3, r3, #PMC_SCRATCH38
  108. mov r12, #1
  109. str r12, [r2] @ flag[cpu] = 1
  110. dsb
  111. str r12, [r1] @ !turn = cpu
  112. 1: dsb
  113. ldr r12, [r3]
  114. cmp r12, #1 @ flag[!cpu] == 1?
  115. ldreq r12, [r1]
  116. cmpeq r12, r0 @ !turn == cpu?
  117. beq 1b @ while !turn == cpu && flag[!cpu] == 1
  118. mov pc, lr @ locked
  119. ENDPROC(tegra_pen_lock)
  120. ENTRY(tegra_pen_unlock)
  121. dsb
  122. mov32 r3, TEGRA_PMC_VIRT
  123. cpu_id r0
  124. cmp r0, #0
  125. addeq r2, r3, #PMC_SCRATCH38
  126. addne r2, r3, #PMC_SCRATCH39
  127. mov r12, #0
  128. str r12, [r2]
  129. mov pc, lr
  130. ENDPROC(tegra_pen_unlock)
  131. /*
  132. * tegra20_cpu_clear_resettable(void)
  133. *
  134. * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when
  135. * it is expected that the secondary CPU will be idle soon.
  136. */
  137. ENTRY(tegra20_cpu_clear_resettable)
  138. mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
  139. mov r12, #CPU_NOT_RESETTABLE
  140. str r12, [r1]
  141. mov pc, lr
  142. ENDPROC(tegra20_cpu_clear_resettable)
  143. /*
  144. * tegra20_cpu_set_resettable_soon(void)
  145. *
  146. * Called to set the "resettable soon" flag in PMC_SCRATCH41 when
  147. * it is expected that the secondary CPU will be idle soon.
  148. */
  149. ENTRY(tegra20_cpu_set_resettable_soon)
  150. mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
  151. mov r12, #CPU_RESETTABLE_SOON
  152. str r12, [r1]
  153. mov pc, lr
  154. ENDPROC(tegra20_cpu_set_resettable_soon)
  155. /*
  156. * tegra20_cpu_is_resettable_soon(void)
  157. *
  158. * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been
  159. * set because it is expected that the secondary CPU will be idle soon.
  160. */
  161. ENTRY(tegra20_cpu_is_resettable_soon)
  162. mov32 r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
  163. ldr r12, [r1]
  164. cmp r12, #CPU_RESETTABLE_SOON
  165. moveq r0, #1
  166. movne r0, #0
  167. mov pc, lr
  168. ENDPROC(tegra20_cpu_is_resettable_soon)
  169. /*
  170. * tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
  171. *
  172. * Enters WFI on secondary CPU by exiting coherency.
  173. */
  174. ENTRY(tegra20_sleep_cpu_secondary_finish)
  175. stmfd sp!, {r4-r11, lr}
  176. mrc p15, 0, r11, c1, c0, 1 @ save actlr before exiting coherency
  177. /* Flush and disable the L1 data cache */
  178. bl tegra_disable_clean_inv_dcache
  179. mov32 r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
  180. mov r3, #CPU_RESETTABLE
  181. str r3, [r0]
  182. bl cpu_do_idle
  183. /*
  184. * cpu may be reset while in wfi, which will return through
  185. * tegra_resume to cpu_resume
  186. * or interrupt may wake wfi, which will return here
  187. * cpu state is unchanged - MMU is on, cache is on, coherency
  188. * is off, and the data cache is off
  189. *
  190. * r11 contains the original actlr
  191. */
  192. bl tegra_pen_lock
  193. mov32 r3, TEGRA_PMC_VIRT
  194. add r0, r3, #PMC_SCRATCH41
  195. mov r3, #CPU_NOT_RESETTABLE
  196. str r3, [r0]
  197. bl tegra_pen_unlock
  198. /* Re-enable the data cache */
  199. mrc p15, 0, r10, c1, c0, 0
  200. orr r10, r10, #CR_C
  201. mcr p15, 0, r10, c1, c0, 0
  202. isb
  203. mcr p15, 0, r11, c1, c0, 1 @ reenable coherency
  204. /* Invalidate the TLBs & BTAC */
  205. mov r1, #0
  206. mcr p15, 0, r1, c8, c3, 0 @ invalidate shared TLBs
  207. mcr p15, 0, r1, c7, c1, 6 @ invalidate shared BTAC
  208. dsb
  209. isb
  210. /* the cpu was running with coherency disabled,
  211. * caches may be out of date */
  212. bl v7_flush_kern_cache_louis
  213. ldmfd sp!, {r4 - r11, pc}
  214. ENDPROC(tegra20_sleep_cpu_secondary_finish)
  215. /*
  216. * tegra20_tear_down_cpu
  217. *
  218. * Switches the CPU cluster to PLL-P and enters sleep.
  219. */
  220. ENTRY(tegra20_tear_down_cpu)
  221. bl tegra_switch_cpu_to_pllp
  222. b tegra20_enter_sleep
  223. ENDPROC(tegra20_tear_down_cpu)
  224. /*
  225. * tegra20_enter_sleep
  226. *
  227. * uses flow controller to enter sleep state
  228. * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
  229. * executes from SDRAM with target state is LP2
  230. */
  231. tegra20_enter_sleep:
  232. mov32 r6, TEGRA_FLOW_CTRL_BASE
  233. mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
  234. orr r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
  235. cpu_id r1
  236. cpu_to_halt_reg r1, r1
  237. str r0, [r6, r1]
  238. dsb
  239. ldr r0, [r6, r1] /* memory barrier */
  240. halted:
  241. dsb
  242. wfe /* CPU should be power gated here */
  243. isb
  244. b halted
  245. #endif