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 */
37ENTRY(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
42ENDPROC(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 */
57ENTRY(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
81ENDPROC(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 */
106ENTRY(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
1201:	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
128ENDPROC(tegra_pen_lock)
129
130ENTRY(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
140ENDPROC(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 */
148ENTRY(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
153ENDPROC(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 */
161ENTRY(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
166ENDPROC(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 */
174ENTRY(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
181ENDPROC(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 */
188ENTRY(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	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}
241ENDPROC(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 */
248ENTRY(tegra20_tear_down_cpu)
249	bl	tegra_switch_cpu_to_pllp
250	b	tegra20_enter_sleep
251ENDPROC(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 */
260tegra20_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
271halted:
272	dsb
273	wfe	/* CPU should be power gated here */
274	isb
275	b	halted
276
277#endif
278