ARM: rockchip: rk3228: implement function rk3228_restart
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-tegra / sleep-tegra20.S
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
21 #include <linux/linkage.h>
22
23 #include <asm/assembler.h>
24 #include <asm/proc-fns.h>
25 #include <asm/cp15.h>
26
27 #include "sleep.h"
28 #include "flowctrl.h"
29
30 #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
31 /*
32  * tegra20_hotplug_shutdown(void)
33  *
34  * puts the current cpu in reset
35  * should never return
36  */
37 ENTRY(tegra20_hotplug_shutdown)
38         /* Put this CPU down */
39         cpu_id  r0
40         bl      tegra20_cpu_shutdown
41         mov     pc, lr                  @ should never get here
42 ENDPROC(tegra20_hotplug_shutdown)
43
44 /*
45  * tegra20_cpu_shutdown(int cpu)
46  *
47  * r0 is cpu to reset
48  *
49  * puts the specified CPU in wait-for-event mode on the flow controller
50  * and puts the CPU in reset
51  * can be called on the current cpu or another cpu
52  * if called on the current cpu, does not return
53  * MUST NOT BE CALLED FOR CPU 0.
54  *
55  * corrupts r0-r3, r12
56  */
57 ENTRY(tegra20_cpu_shutdown)
58         cmp     r0, #0
59         moveq   pc, lr                  @ must not be called for CPU 0
60         mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
61         mov     r12, #CPU_RESETTABLE
62         str     r12, [r1]
63
64         cpu_to_halt_reg r1, r0
65         ldr     r3, =TEGRA_FLOW_CTRL_VIRT
66         mov     r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
67         str     r2, [r3, r1]            @ put flow controller in wait event mode
68         ldr     r2, [r3, r1]
69         isb
70         dsb
71         movw    r1, 0x1011
72         mov     r1, r1, lsl r0
73         ldr     r3, =TEGRA_CLK_RESET_VIRT
74         str     r1, [r3, #0x340]        @ put slave CPU in reset
75         isb
76         dsb
77         cpu_id  r3
78         cmp     r3, r0
79         beq     .
80         mov     pc, lr
81 ENDPROC(tegra20_cpu_shutdown)
82 #endif
83
84 #ifdef CONFIG_PM_SLEEP
85 /*
86  * tegra_pen_lock
87  *
88  * spinlock implementation with no atomic test-and-set and no coherence
89  * using Peterson's algorithm on strongly-ordered registers
90  * used to synchronize a cpu waking up from wfi with entering lp2 on idle
91  *
92  * The reference link of Peterson's algorithm:
93  * http://en.wikipedia.org/wiki/Peterson's_algorithm
94  *
95  * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
96  * on cpu 0:
97  * r2 = flag[0] (in SCRATCH38)
98  * r3 = flag[1] (in SCRATCH39)
99  * on cpu1:
100  * r2 = flag[1] (in SCRATCH39)
101  * r3 = flag[0] (in SCRATCH38)
102  *
103  * must be called with MMU on
104  * corrupts r0-r3, r12
105  */
106 ENTRY(tegra_pen_lock)
107         mov32   r3, TEGRA_PMC_VIRT
108         cpu_id  r0
109         add     r1, r3, #PMC_SCRATCH37
110         cmp     r0, #0
111         addeq   r2, r3, #PMC_SCRATCH38
112         addeq   r3, r3, #PMC_SCRATCH39
113         addne   r2, r3, #PMC_SCRATCH39
114         addne   r3, r3, #PMC_SCRATCH38
115
116         mov     r12, #1
117         str     r12, [r2]               @ flag[cpu] = 1
118         dsb
119         str     r12, [r1]               @ !turn = cpu
120 1:      dsb
121         ldr     r12, [r3]
122         cmp     r12, #1                 @ flag[!cpu] == 1?
123         ldreq   r12, [r1]
124         cmpeq   r12, r0                 @ !turn == cpu?
125         beq     1b                      @ while !turn == cpu && flag[!cpu] == 1
126
127         mov     pc, lr                  @ locked
128 ENDPROC(tegra_pen_lock)
129
130 ENTRY(tegra_pen_unlock)
131         dsb
132         mov32   r3, TEGRA_PMC_VIRT
133         cpu_id  r0
134         cmp     r0, #0
135         addeq   r2, r3, #PMC_SCRATCH38
136         addne   r2, r3, #PMC_SCRATCH39
137         mov     r12, #0
138         str     r12, [r2]
139         mov     pc, lr
140 ENDPROC(tegra_pen_unlock)
141
142 /*
143  * tegra20_cpu_clear_resettable(void)
144  *
145  * Called to clear the "resettable soon" flag in PMC_SCRATCH41 when
146  * it is expected that the secondary CPU will be idle soon.
147  */
148 ENTRY(tegra20_cpu_clear_resettable)
149         mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
150         mov     r12, #CPU_NOT_RESETTABLE
151         str     r12, [r1]
152         mov     pc, lr
153 ENDPROC(tegra20_cpu_clear_resettable)
154
155 /*
156  * tegra20_cpu_set_resettable_soon(void)
157  *
158  * Called to set the "resettable soon" flag in PMC_SCRATCH41 when
159  * it is expected that the secondary CPU will be idle soon.
160  */
161 ENTRY(tegra20_cpu_set_resettable_soon)
162         mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
163         mov     r12, #CPU_RESETTABLE_SOON
164         str     r12, [r1]
165         mov     pc, lr
166 ENDPROC(tegra20_cpu_set_resettable_soon)
167
168 /*
169  * tegra20_cpu_is_resettable_soon(void)
170  *
171  * Returns true if the "resettable soon" flag in PMC_SCRATCH41 has been
172  * set because it is expected that the secondary CPU will be idle soon.
173  */
174 ENTRY(tegra20_cpu_is_resettable_soon)
175         mov32   r1, TEGRA_PMC_VIRT + PMC_SCRATCH41
176         ldr     r12, [r1]
177         cmp     r12, #CPU_RESETTABLE_SOON
178         moveq   r0, #1
179         movne   r0, #0
180         mov     pc, lr
181 ENDPROC(tegra20_cpu_is_resettable_soon)
182
183 /*
184  * tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
185  *
186  * Enters WFI on secondary CPU by exiting coherency.
187  */
188 ENTRY(tegra20_sleep_cpu_secondary_finish)
189         stmfd   sp!, {r4-r11, lr}
190
191         mrc     p15, 0, r11, c1, c0, 1  @ save actlr before exiting coherency
192
193         /* Flush and disable the L1 data cache */
194         bl      tegra_disable_clean_inv_dcache
195
196         mov32   r0, TEGRA_PMC_VIRT + PMC_SCRATCH41
197         mov     r3, #CPU_RESETTABLE
198         str     r3, [r0]
199
200         bl      tegra_cpu_do_idle
201
202         /*
203          * cpu may be reset while in wfi, which will return through
204          * tegra_resume to cpu_resume
205          * or interrupt may wake wfi, which will return here
206          * cpu state is unchanged - MMU is on, cache is on, coherency
207          * is off, and the data cache is off
208          *
209          * r11 contains the original actlr
210          */
211
212         bl      tegra_pen_lock
213
214         mov32   r3, TEGRA_PMC_VIRT
215         add     r0, r3, #PMC_SCRATCH41
216         mov     r3, #CPU_NOT_RESETTABLE
217         str     r3, [r0]
218
219         bl      tegra_pen_unlock
220
221         /* Re-enable the data cache */
222         mrc     p15, 0, r10, c1, c0, 0
223         orr     r10, r10, #CR_C
224         mcr     p15, 0, r10, c1, c0, 0
225         isb
226
227         mcr     p15, 0, r11, c1, c0, 1  @ reenable coherency
228
229         /* Invalidate the TLBs & BTAC */
230         mov     r1, #0
231         mcr     p15, 0, r1, c8, c3, 0   @ invalidate shared TLBs
232         mcr     p15, 0, r1, c7, c1, 6   @ invalidate shared BTAC
233         dsb
234         isb
235
236         /* the cpu was running with coherency disabled,
237          * caches may be out of date */
238         bl      v7_flush_kern_cache_louis
239
240         ldmfd   sp!, {r4 - r11, pc}
241 ENDPROC(tegra20_sleep_cpu_secondary_finish)
242
243 /*
244  * tegra20_tear_down_cpu
245  *
246  * Switches the CPU cluster to PLL-P and enters sleep.
247  */
248 ENTRY(tegra20_tear_down_cpu)
249         bl      tegra_switch_cpu_to_pllp
250         b       tegra20_enter_sleep
251 ENDPROC(tegra20_tear_down_cpu)
252
253 /*
254  * tegra20_enter_sleep
255  *
256  * uses flow controller to enter sleep state
257  * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
258  * executes from SDRAM with target state is LP2
259  */
260 tegra20_enter_sleep:
261         mov32   r6, TEGRA_FLOW_CTRL_BASE
262
263         mov     r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
264         orr     r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
265         cpu_id  r1
266         cpu_to_halt_reg r1, r1
267         str     r0, [r6, r1]
268         dsb
269         ldr     r0, [r6, r1] /* memory barrier */
270
271 halted:
272         dsb
273         wfe     /* CPU should be power gated here */
274         isb
275         b       halted
276
277 #endif