xref: /linux/arch/arm/mach-tegra/sleep-tegra20.S (revision c0c914eca7f251c70facc37dfebeaf176601918d)
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#include <asm/cache.h>
27
28#include "irammap.h"
29#include "sleep.h"
30#include "flowctrl.h"
31
32#define EMC_CFG				0xc
33#define EMC_ADR_CFG			0x10
34#define EMC_REFRESH			0x70
35#define EMC_NOP				0xdc
36#define EMC_SELF_REF			0xe0
37#define EMC_REQ_CTRL			0x2b0
38#define EMC_EMC_STATUS			0x2b4
39
40#define CLK_RESET_CCLK_BURST		0x20
41#define CLK_RESET_CCLK_DIVIDER		0x24
42#define CLK_RESET_SCLK_BURST		0x28
43#define CLK_RESET_SCLK_DIVIDER		0x2c
44#define CLK_RESET_PLLC_BASE		0x80
45#define CLK_RESET_PLLM_BASE		0x90
46#define CLK_RESET_PLLP_BASE		0xa0
47
48#define APB_MISC_XM2CFGCPADCTRL		0x8c8
49#define APB_MISC_XM2CFGDPADCTRL		0x8cc
50#define APB_MISC_XM2CLKCFGPADCTRL	0x8d0
51#define APB_MISC_XM2COMPPADCTRL		0x8d4
52#define APB_MISC_XM2VTTGENPADCTRL	0x8d8
53#define APB_MISC_XM2CFGCPADCTRL2	0x8e4
54#define APB_MISC_XM2CFGDPADCTRL2	0x8e8
55
56.macro pll_enable, rd, r_car_base, pll_base
57	ldr	\rd, [\r_car_base, #\pll_base]
58	tst	\rd, #(1 << 30)
59	orreq	\rd, \rd, #(1 << 30)
60	streq	\rd, [\r_car_base, #\pll_base]
61.endm
62
63.macro emc_device_mask, rd, base
64	ldr	\rd, [\base, #EMC_ADR_CFG]
65	tst	\rd, #(0x3 << 24)
66	moveq	\rd, #(0x1 << 8)		@ just 1 device
67	movne	\rd, #(0x3 << 8)		@ 2 devices
68.endm
69
70#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
71/*
72 * tegra20_hotplug_shutdown(void)
73 *
74 * puts the current cpu in reset
75 * should never return
76 */
77ENTRY(tegra20_hotplug_shutdown)
78	/* Put this CPU down */
79	cpu_id	r0
80	bl	tegra20_cpu_shutdown
81	ret	lr			@ should never get here
82ENDPROC(tegra20_hotplug_shutdown)
83
84/*
85 * tegra20_cpu_shutdown(int cpu)
86 *
87 * r0 is cpu to reset
88 *
89 * puts the specified CPU in wait-for-event mode on the flow controller
90 * and puts the CPU in reset
91 * can be called on the current cpu or another cpu
92 * if called on the current cpu, does not return
93 * MUST NOT BE CALLED FOR CPU 0.
94 *
95 * corrupts r0-r3, r12
96 */
97ENTRY(tegra20_cpu_shutdown)
98	cmp	r0, #0
99	reteq	lr			@ must not be called for CPU 0
100	mov32	r1, TEGRA_IRAM_RESET_BASE_VIRT
101	ldr	r2, =__tegra20_cpu1_resettable_status_offset
102	mov	r12, #CPU_RESETTABLE
103	strb	r12, [r1, r2]
104
105	cpu_to_halt_reg r1, r0
106	ldr	r3, =TEGRA_FLOW_CTRL_VIRT
107	mov	r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
108	str	r2, [r3, r1]		@ put flow controller in wait event mode
109	ldr	r2, [r3, r1]
110	isb
111	dsb
112	movw	r1, 0x1011
113	mov	r1, r1, lsl r0
114	ldr	r3, =TEGRA_CLK_RESET_VIRT
115	str	r1, [r3, #0x340]	@ put slave CPU in reset
116	isb
117	dsb
118	cpu_id	r3
119	cmp	r3, r0
120	beq	.
121	ret	lr
122ENDPROC(tegra20_cpu_shutdown)
123#endif
124
125#ifdef CONFIG_PM_SLEEP
126/*
127 * tegra_pen_lock
128 *
129 * spinlock implementation with no atomic test-and-set and no coherence
130 * using Peterson's algorithm on strongly-ordered registers
131 * used to synchronize a cpu waking up from wfi with entering lp2 on idle
132 *
133 * The reference link of Peterson's algorithm:
134 * http://en.wikipedia.org/wiki/Peterson's_algorithm
135 *
136 * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
137 * on cpu 0:
138 * r2 = flag[0] (in SCRATCH38)
139 * r3 = flag[1] (in SCRATCH39)
140 * on cpu1:
141 * r2 = flag[1] (in SCRATCH39)
142 * r3 = flag[0] (in SCRATCH38)
143 *
144 * must be called with MMU on
145 * corrupts r0-r3, r12
146 */
147ENTRY(tegra_pen_lock)
148	mov32	r3, TEGRA_PMC_VIRT
149	cpu_id	r0
150	add	r1, r3, #PMC_SCRATCH37
151	cmp	r0, #0
152	addeq	r2, r3, #PMC_SCRATCH38
153	addeq	r3, r3, #PMC_SCRATCH39
154	addne	r2, r3, #PMC_SCRATCH39
155	addne	r3, r3, #PMC_SCRATCH38
156
157	mov	r12, #1
158	str	r12, [r2]		@ flag[cpu] = 1
159	dsb
160	str	r12, [r1]		@ !turn = cpu
1611:	dsb
162	ldr	r12, [r3]
163	cmp	r12, #1			@ flag[!cpu] == 1?
164	ldreq	r12, [r1]
165	cmpeq	r12, r0			@ !turn == cpu?
166	beq	1b			@ while !turn == cpu && flag[!cpu] == 1
167
168	ret	lr			@ locked
169ENDPROC(tegra_pen_lock)
170
171ENTRY(tegra_pen_unlock)
172	dsb
173	mov32	r3, TEGRA_PMC_VIRT
174	cpu_id	r0
175	cmp	r0, #0
176	addeq	r2, r3, #PMC_SCRATCH38
177	addne	r2, r3, #PMC_SCRATCH39
178	mov	r12, #0
179	str	r12, [r2]
180	ret     lr
181ENDPROC(tegra_pen_unlock)
182
183/*
184 * tegra20_cpu_clear_resettable(void)
185 *
186 * Called to clear the "resettable soon" flag in IRAM variable when
187 * it is expected that the secondary CPU will be idle soon.
188 */
189ENTRY(tegra20_cpu_clear_resettable)
190	mov32	r1, TEGRA_IRAM_RESET_BASE_VIRT
191	ldr	r2, =__tegra20_cpu1_resettable_status_offset
192	mov	r12, #CPU_NOT_RESETTABLE
193	strb	r12, [r1, r2]
194	ret	lr
195ENDPROC(tegra20_cpu_clear_resettable)
196
197/*
198 * tegra20_cpu_set_resettable_soon(void)
199 *
200 * Called to set the "resettable soon" flag in IRAM variable when
201 * it is expected that the secondary CPU will be idle soon.
202 */
203ENTRY(tegra20_cpu_set_resettable_soon)
204	mov32	r1, TEGRA_IRAM_RESET_BASE_VIRT
205	ldr	r2, =__tegra20_cpu1_resettable_status_offset
206	mov	r12, #CPU_RESETTABLE_SOON
207	strb	r12, [r1, r2]
208	ret	lr
209ENDPROC(tegra20_cpu_set_resettable_soon)
210
211/*
212 * tegra20_cpu_is_resettable_soon(void)
213 *
214 * Returns true if the "resettable soon" flag in IRAM variable has been
215 * set because it is expected that the secondary CPU will be idle soon.
216 */
217ENTRY(tegra20_cpu_is_resettable_soon)
218	mov32	r1, TEGRA_IRAM_RESET_BASE_VIRT
219	ldr	r2, =__tegra20_cpu1_resettable_status_offset
220	ldrb	r12, [r1, r2]
221	cmp	r12, #CPU_RESETTABLE_SOON
222	moveq	r0, #1
223	movne	r0, #0
224	ret	lr
225ENDPROC(tegra20_cpu_is_resettable_soon)
226
227/*
228 * tegra20_sleep_core_finish(unsigned long v2p)
229 *
230 * Enters suspend in LP0 or LP1 by turning off the mmu and jumping to
231 * tegra20_tear_down_core in IRAM
232 */
233ENTRY(tegra20_sleep_core_finish)
234	mov     r4, r0
235	/* Flush, disable the L1 data cache and exit SMP */
236	mov     r0, #TEGRA_FLUSH_CACHE_ALL
237	bl	tegra_disable_clean_inv_dcache
238	mov     r0, r4
239
240	mov32	r3, tegra_shut_off_mmu
241	add	r3, r3, r0
242
243	mov32	r0, tegra20_tear_down_core
244	mov32	r1, tegra20_iram_start
245	sub	r0, r0, r1
246	mov32	r1, TEGRA_IRAM_LPx_RESUME_AREA
247	add	r0, r0, r1
248
249	ret	r3
250ENDPROC(tegra20_sleep_core_finish)
251
252/*
253 * tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
254 *
255 * Enters WFI on secondary CPU by exiting coherency.
256 */
257ENTRY(tegra20_sleep_cpu_secondary_finish)
258	stmfd	sp!, {r4-r11, lr}
259
260	mrc	p15, 0, r11, c1, c0, 1  @ save actlr before exiting coherency
261
262	/* Flush and disable the L1 data cache */
263	mov	r0, #TEGRA_FLUSH_CACHE_LOUIS
264	bl	tegra_disable_clean_inv_dcache
265
266	mov32	r0, TEGRA_IRAM_RESET_BASE_VIRT
267	ldr	r4, =__tegra20_cpu1_resettable_status_offset
268	mov	r3, #CPU_RESETTABLE
269	strb	r3, [r0, r4]
270
271	bl	tegra_cpu_do_idle
272
273	/*
274	 * cpu may be reset while in wfi, which will return through
275	 * tegra_resume to cpu_resume
276	 * or interrupt may wake wfi, which will return here
277	 * cpu state is unchanged - MMU is on, cache is on, coherency
278	 * is off, and the data cache is off
279	 *
280	 * r11 contains the original actlr
281	 */
282
283	bl	tegra_pen_lock
284
285	mov32	r0, TEGRA_IRAM_RESET_BASE_VIRT
286	ldr	r4, =__tegra20_cpu1_resettable_status_offset
287	mov	r3, #CPU_NOT_RESETTABLE
288	strb	r3, [r0, r4]
289
290	bl	tegra_pen_unlock
291
292	/* Re-enable the data cache */
293	mrc	p15, 0, r10, c1, c0, 0
294	orr	r10, r10, #CR_C
295	mcr	p15, 0, r10, c1, c0, 0
296	isb
297
298	mcr	p15, 0, r11, c1, c0, 1	@ reenable coherency
299
300	/* Invalidate the TLBs & BTAC */
301	mov	r1, #0
302	mcr	p15, 0, r1, c8, c3, 0	@ invalidate shared TLBs
303	mcr	p15, 0, r1, c7, c1, 6	@ invalidate shared BTAC
304	dsb
305	isb
306
307	/* the cpu was running with coherency disabled,
308	 * caches may be out of date */
309	bl	v7_flush_kern_cache_louis
310
311	ldmfd	sp!, {r4 - r11, pc}
312ENDPROC(tegra20_sleep_cpu_secondary_finish)
313
314/*
315 * tegra20_tear_down_cpu
316 *
317 * Switches the CPU cluster to PLL-P and enters sleep.
318 */
319ENTRY(tegra20_tear_down_cpu)
320	bl	tegra_switch_cpu_to_pllp
321	b	tegra20_enter_sleep
322ENDPROC(tegra20_tear_down_cpu)
323
324/* START OF ROUTINES COPIED TO IRAM */
325	.align L1_CACHE_SHIFT
326	.globl tegra20_iram_start
327tegra20_iram_start:
328
329/*
330 * tegra20_lp1_reset
331 *
332 * reset vector for LP1 restore; copied into IRAM during suspend.
333 * Brings the system back up to a safe staring point (SDRAM out of
334 * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP,
335 * system clock running on the same PLL that it suspended at), and
336 * jumps to tegra_resume to restore virtual addressing and PLLX.
337 * The physical address of tegra_resume expected to be stored in
338 * PMC_SCRATCH41.
339 *
340 * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_LPx_RESUME_AREA.
341 */
342ENTRY(tegra20_lp1_reset)
343	/*
344	 * The CPU and system bus are running at 32KHz and executing from
345	 * IRAM when this code is executed; immediately switch to CLKM and
346	 * enable PLLM, PLLP, PLLC.
347	 */
348	mov32	r0, TEGRA_CLK_RESET_BASE
349
350	mov	r1, #(1 << 28)
351	str	r1, [r0, #CLK_RESET_SCLK_BURST]
352	str	r1, [r0, #CLK_RESET_CCLK_BURST]
353	mov	r1, #0
354	str	r1, [r0, #CLK_RESET_CCLK_DIVIDER]
355	str	r1, [r0, #CLK_RESET_SCLK_DIVIDER]
356
357	pll_enable r1, r0, CLK_RESET_PLLM_BASE
358	pll_enable r1, r0, CLK_RESET_PLLP_BASE
359	pll_enable r1, r0, CLK_RESET_PLLC_BASE
360
361	adr	r2, tegra20_sdram_pad_address
362	adr	r4, tegra20_sdram_pad_save
363	mov	r5, #0
364
365	ldr	r6, tegra20_sdram_pad_size
366padload:
367	ldr	r7, [r2, r5]		@ r7 is the addr in the pad_address
368
369	ldr	r1, [r4, r5]
370	str	r1, [r7]		@ restore the value in pad_save
371
372	add	r5, r5, #4
373	cmp	r6, r5
374	bne	padload
375
376padload_done:
377	/* 255uS delay for PLL stabilization */
378	mov32	r7, TEGRA_TMRUS_BASE
379	ldr	r1, [r7]
380	add	r1, r1, #0xff
381	wait_until r1, r7, r9
382
383	adr	r4, tegra20_sclk_save
384	ldr	r4, [r4]
385	str	r4, [r0, #CLK_RESET_SCLK_BURST]
386	mov32	r4, ((1 << 28) | (4))	@ burst policy is PLLP
387	str	r4, [r0, #CLK_RESET_CCLK_BURST]
388
389	mov32	r0, TEGRA_EMC_BASE
390	ldr	r1, [r0, #EMC_CFG]
391	bic	r1, r1, #(1 << 31)	@ disable DRAM_CLK_STOP
392	str	r1, [r0, #EMC_CFG]
393
394	mov	r1, #0
395	str	r1, [r0, #EMC_SELF_REF]	@ take DRAM out of self refresh
396	mov	r1, #1
397	str	r1, [r0, #EMC_NOP]
398	str	r1, [r0, #EMC_NOP]
399	str	r1, [r0, #EMC_REFRESH]
400
401	emc_device_mask r1, r0
402
403exit_selfrefresh_loop:
404	ldr	r2, [r0, #EMC_EMC_STATUS]
405	ands	r2, r2, r1
406	bne	exit_selfrefresh_loop
407
408	mov	r1, #0			@ unstall all transactions
409	str	r1, [r0, #EMC_REQ_CTRL]
410
411	mov32	r0, TEGRA_PMC_BASE
412	ldr	r0, [r0, #PMC_SCRATCH41]
413	ret	r0			@ jump to tegra_resume
414ENDPROC(tegra20_lp1_reset)
415
416/*
417 * tegra20_tear_down_core
418 *
419 * copied into and executed from IRAM
420 * puts memory in self-refresh for LP0 and LP1
421 */
422tegra20_tear_down_core:
423	bl	tegra20_sdram_self_refresh
424	bl	tegra20_switch_cpu_to_clk32k
425	b	tegra20_enter_sleep
426
427/*
428 * tegra20_switch_cpu_to_clk32k
429 *
430 * In LP0 and LP1 all PLLs will be turned off. Switch the CPU and system clock
431 * to the 32KHz clock.
432 */
433tegra20_switch_cpu_to_clk32k:
434	/*
435	 * start by switching to CLKM to safely disable PLLs, then switch to
436	 * CLKS.
437	 */
438	mov	r0, #(1 << 28)
439	str	r0, [r5, #CLK_RESET_SCLK_BURST]
440	str	r0, [r5, #CLK_RESET_CCLK_BURST]
441	mov	r0, #0
442	str	r0, [r5, #CLK_RESET_CCLK_DIVIDER]
443	str	r0, [r5, #CLK_RESET_SCLK_DIVIDER]
444
445	/* 2uS delay delay between changing SCLK and disabling PLLs */
446	mov32	r7, TEGRA_TMRUS_BASE
447	ldr	r1, [r7]
448	add	r1, r1, #2
449	wait_until r1, r7, r9
450
451	/* disable PLLM, PLLP and PLLC */
452	ldr	r0, [r5, #CLK_RESET_PLLM_BASE]
453	bic	r0, r0, #(1 << 30)
454	str	r0, [r5, #CLK_RESET_PLLM_BASE]
455	ldr	r0, [r5, #CLK_RESET_PLLP_BASE]
456	bic	r0, r0, #(1 << 30)
457	str	r0, [r5, #CLK_RESET_PLLP_BASE]
458	ldr	r0, [r5, #CLK_RESET_PLLC_BASE]
459	bic	r0, r0, #(1 << 30)
460	str	r0, [r5, #CLK_RESET_PLLC_BASE]
461
462	/* switch to CLKS */
463	mov	r0, #0	/* brust policy = 32KHz */
464	str	r0, [r5, #CLK_RESET_SCLK_BURST]
465
466	ret	lr
467
468/*
469 * tegra20_enter_sleep
470 *
471 * uses flow controller to enter sleep state
472 * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
473 * executes from SDRAM with target state is LP2
474 */
475tegra20_enter_sleep:
476	mov32   r6, TEGRA_FLOW_CTRL_BASE
477
478	mov     r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
479	orr	r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
480	cpu_id	r1
481	cpu_to_halt_reg r1, r1
482	str	r0, [r6, r1]
483	dsb
484	ldr	r0, [r6, r1] /* memory barrier */
485
486halted:
487	dsb
488	wfe	/* CPU should be power gated here */
489	isb
490	b	halted
491
492/*
493 * tegra20_sdram_self_refresh
494 *
495 * called with MMU off and caches disabled
496 * puts sdram in self refresh
497 * must be executed from IRAM
498 */
499tegra20_sdram_self_refresh:
500	mov32	r1, TEGRA_EMC_BASE	@ r1 reserved for emc base addr
501
502	mov	r2, #3
503	str	r2, [r1, #EMC_REQ_CTRL]	@ stall incoming DRAM requests
504
505emcidle:
506	ldr	r2, [r1, #EMC_EMC_STATUS]
507	tst	r2, #4
508	beq	emcidle
509
510	mov	r2, #1
511	str	r2, [r1, #EMC_SELF_REF]
512
513	emc_device_mask r2, r1
514
515emcself:
516	ldr	r3, [r1, #EMC_EMC_STATUS]
517	and	r3, r3, r2
518	cmp	r3, r2
519	bne	emcself			@ loop until DDR in self-refresh
520
521	adr	r2, tegra20_sdram_pad_address
522	adr	r3, tegra20_sdram_pad_safe
523	adr	r4, tegra20_sdram_pad_save
524	mov	r5, #0
525
526	ldr	r6, tegra20_sdram_pad_size
527padsave:
528	ldr	r0, [r2, r5]		@ r0 is the addr in the pad_address
529
530	ldr	r1, [r0]
531	str	r1, [r4, r5]		@ save the content of the addr
532
533	ldr	r1, [r3, r5]
534	str	r1, [r0]		@ set the save val to the addr
535
536	add	r5, r5, #4
537	cmp	r6, r5
538	bne	padsave
539padsave_done:
540
541	mov32	r5, TEGRA_CLK_RESET_BASE
542	ldr	r0, [r5, #CLK_RESET_SCLK_BURST]
543	adr	r2, tegra20_sclk_save
544	str	r0, [r2]
545	dsb
546	ret	lr
547
548tegra20_sdram_pad_address:
549	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL
550	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL
551	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CLKCFGPADCTRL
552	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2COMPPADCTRL
553	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2VTTGENPADCTRL
554	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL2
555	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL2
556
557tegra20_sdram_pad_size:
558	.word	tegra20_sdram_pad_size - tegra20_sdram_pad_address
559
560tegra20_sdram_pad_safe:
561	.word	0x8
562	.word	0x8
563	.word	0x0
564	.word	0x8
565	.word	0x5500
566	.word	0x08080040
567	.word	0x0
568
569tegra20_sclk_save:
570	.word	0x0
571
572tegra20_sdram_pad_save:
573	.rept (tegra20_sdram_pad_size - tegra20_sdram_pad_address) / 4
574	.long	0
575	.endr
576
577	.ltorg
578/* dummy symbol for end of IRAM */
579	.align L1_CACHE_SHIFT
580	.globl tegra20_iram_end
581tegra20_iram_end:
582	b	.
583#endif
584