xref: /linux/arch/arm/mach-tegra/sleep-tegra20.S (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
4 * Copyright (c) 2011, Google, Inc.
5 *
6 * Author: Colin Cross <ccross@android.com>
7 *         Gary King <gking@nvidia.com>
8 */
9
10#include <linux/linkage.h>
11
12#include <soc/tegra/flowctrl.h>
13
14#include <asm/assembler.h>
15#include <asm/proc-fns.h>
16#include <asm/cp15.h>
17#include <asm/cache.h>
18
19#include "irammap.h"
20#include "reset.h"
21#include "sleep.h"
22
23#define EMC_CFG				0xc
24#define EMC_ADR_CFG			0x10
25#define EMC_NOP				0xdc
26#define EMC_SELF_REF			0xe0
27#define EMC_REQ_CTRL			0x2b0
28#define EMC_EMC_STATUS			0x2b4
29
30#define CLK_RESET_CCLK_BURST		0x20
31#define CLK_RESET_CCLK_DIVIDER		0x24
32#define CLK_RESET_SCLK_BURST		0x28
33#define CLK_RESET_SCLK_DIVIDER		0x2c
34#define CLK_RESET_PLLC_BASE		0x80
35#define CLK_RESET_PLLM_BASE		0x90
36#define CLK_RESET_PLLP_BASE		0xa0
37
38#define APB_MISC_XM2CFGCPADCTRL		0x8c8
39#define APB_MISC_XM2CFGDPADCTRL		0x8cc
40#define APB_MISC_XM2CLKCFGPADCTRL	0x8d0
41#define APB_MISC_XM2COMPPADCTRL		0x8d4
42#define APB_MISC_XM2VTTGENPADCTRL	0x8d8
43#define APB_MISC_XM2CFGCPADCTRL2	0x8e4
44#define APB_MISC_XM2CFGDPADCTRL2	0x8e8
45
46#define PLLC_STORE_MASK			(1 << 0)
47#define PLLM_STORE_MASK			(1 << 1)
48#define PLLP_STORE_MASK			(1 << 2)
49
50.arch armv7-a
51
52.macro test_pll_state, rd, test_mask
53	ldr	\rd, tegra_pll_state
54	tst	\rd, #\test_mask
55.endm
56
57.macro store_pll_state, rd, tmp, r_car_base, pll_base, pll_mask
58	ldr	\rd, [\r_car_base, #\pll_base]
59	tst	\rd, #(1 << 30)
60	ldr	\rd, tegra_pll_state
61	biceq	\rd, \rd, #\pll_mask
62	orrne	\rd, \rd, #\pll_mask
63	adr	\tmp, tegra_pll_state
64	str	\rd, [\tmp]
65.endm
66
67.macro pll_enable, rd, r_car_base, pll_base, test_mask
68	test_pll_state \rd, \test_mask
69	beq	1f
70
71	ldr	\rd, [\r_car_base, #\pll_base]
72	tst	\rd, #(1 << 30)
73	orreq	\rd, \rd, #(1 << 30)
74	streq	\rd, [\r_car_base, #\pll_base]
751:
76.endm
77
78.macro emc_device_mask, rd, base
79	ldr	\rd, [\base, #EMC_ADR_CFG]
80	tst	\rd, #(0x3 << 24)
81	moveq	\rd, #(0x1 << 8)		@ just 1 device
82	movne	\rd, #(0x3 << 8)		@ 2 devices
83.endm
84
85#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
86/*
87 * tegra20_hotplug_shutdown(void)
88 *
89 * puts the current cpu in reset
90 * should never return
91 */
92ENTRY(tegra20_hotplug_shutdown)
93	/* Put this CPU down */
94	cpu_id	r0
95	bl	tegra20_cpu_shutdown
96	ret	lr			@ should never get here
97ENDPROC(tegra20_hotplug_shutdown)
98
99/*
100 * tegra20_cpu_shutdown(int cpu)
101 *
102 * r0 is cpu to reset
103 *
104 * puts the specified CPU in wait-for-event mode on the flow controller
105 * and puts the CPU in reset
106 * can be called on the current cpu or another cpu
107 * if called on the current cpu, does not return
108 * MUST NOT BE CALLED FOR CPU 0.
109 *
110 * corrupts r0-r3, r12
111 */
112ENTRY(tegra20_cpu_shutdown)
113	cmp	r0, #0
114	reteq	lr			@ must not be called for CPU 0
115
116	cpu_to_halt_reg r1, r0
117	ldr	r3, =TEGRA_FLOW_CTRL_VIRT
118	mov	r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
119	str	r2, [r3, r1]		@ put flow controller in wait event mode
120	ldr	r2, [r3, r1]
121	isb
122	dsb
123	movw	r1, 0x1011
124	mov	r1, r1, lsl r0
125	ldr	r3, =TEGRA_CLK_RESET_VIRT
126	str	r1, [r3, #0x340]	@ put slave CPU in reset
127	isb
128	dsb
129	cpu_id	r3
130	cmp	r3, r0
131	beq	.
132	ret	lr
133ENDPROC(tegra20_cpu_shutdown)
134#endif
135
136#ifdef CONFIG_PM_SLEEP
137/*
138 * tegra20_sleep_core_finish(unsigned long v2p)
139 *
140 * Enters suspend in LP0 or LP1 by turning off the mmu and jumping to
141 * tegra20_tear_down_core in IRAM
142 */
143ENTRY(tegra20_sleep_core_finish)
144	mov     r4, r0
145	/* Flush, disable the L1 data cache and exit SMP */
146	mov     r0, #TEGRA_FLUSH_CACHE_ALL
147	bl	tegra_disable_clean_inv_dcache
148	mov     r0, r4
149
150	mov32	r3, tegra_shut_off_mmu
151	add	r3, r3, r0
152
153	mov32	r0, tegra20_tear_down_core
154	mov32	r1, tegra20_iram_start
155	sub	r0, r0, r1
156	mov32	r1, TEGRA_IRAM_LPx_RESUME_AREA
157	add	r0, r0, r1
158
159	ret	r3
160ENDPROC(tegra20_sleep_core_finish)
161
162/*
163 * tegra20_tear_down_cpu
164 *
165 * Switches the CPU cluster to PLL-P and enters sleep.
166 */
167ENTRY(tegra20_tear_down_cpu)
168	bl	tegra_switch_cpu_to_pllp
169	b	tegra20_enter_sleep
170ENDPROC(tegra20_tear_down_cpu)
171
172/* START OF ROUTINES COPIED TO IRAM */
173	.align L1_CACHE_SHIFT
174	.globl tegra20_iram_start
175tegra20_iram_start:
176
177/*
178 * tegra20_lp1_reset
179 *
180 * reset vector for LP1 restore; copied into IRAM during suspend.
181 * Brings the system back up to a safe staring point (SDRAM out of
182 * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP,
183 * system clock running on the same PLL that it suspended at), and
184 * jumps to tegra_resume to restore virtual addressing and PLLX.
185 * The physical address of tegra_resume expected to be stored in
186 * PMC_SCRATCH41.
187 *
188 * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_LPx_RESUME_AREA.
189 */
190ENTRY(tegra20_lp1_reset)
191	/*
192	 * The CPU and system bus are running at 32KHz and executing from
193	 * IRAM when this code is executed; immediately switch to CLKM and
194	 * enable PLLM, PLLP, PLLC.
195	 */
196	mov32	r0, TEGRA_CLK_RESET_BASE
197
198	mov	r1, #(1 << 28)
199	str	r1, [r0, #CLK_RESET_SCLK_BURST]
200	str	r1, [r0, #CLK_RESET_CCLK_BURST]
201	mov	r1, #0
202	str	r1, [r0, #CLK_RESET_CCLK_DIVIDER]
203	str	r1, [r0, #CLK_RESET_SCLK_DIVIDER]
204
205	pll_enable r1, r0, CLK_RESET_PLLM_BASE, PLLM_STORE_MASK
206	pll_enable r1, r0, CLK_RESET_PLLP_BASE, PLLP_STORE_MASK
207	pll_enable r1, r0, CLK_RESET_PLLC_BASE, PLLC_STORE_MASK
208
209	adr	r2, tegra20_sdram_pad_address
210	adr	r4, tegra20_sdram_pad_save
211	mov	r5, #0
212
213	ldr	r6, tegra20_sdram_pad_size
214padload:
215	ldr	r7, [r2, r5]		@ r7 is the addr in the pad_address
216
217	ldr	r1, [r4, r5]
218	str	r1, [r7]		@ restore the value in pad_save
219
220	add	r5, r5, #4
221	cmp	r6, r5
222	bne	padload
223
224padload_done:
225	/* 255uS delay for PLL stabilization */
226	mov32	r7, TEGRA_TMRUS_BASE
227	ldr	r1, [r7]
228	add	r1, r1, #0xff
229	wait_until r1, r7, r9
230
231	adr	r4, tegra20_sclk_save
232	ldr	r4, [r4]
233	str	r4, [r0, #CLK_RESET_SCLK_BURST]
234	mov32	r4, ((1 << 28) | (4))	@ burst policy is PLLP
235	str	r4, [r0, #CLK_RESET_CCLK_BURST]
236
237	mov32	r0, TEGRA_EMC_BASE
238	ldr	r1, [r0, #EMC_CFG]
239	bic	r1, r1, #(1 << 31)	@ disable DRAM_CLK_STOP
240	str	r1, [r0, #EMC_CFG]
241
242	mov	r1, #0
243	str	r1, [r0, #EMC_SELF_REF]	@ take DRAM out of self refresh
244	mov	r1, #1
245	str	r1, [r0, #EMC_NOP]
246	str	r1, [r0, #EMC_NOP]
247
248	emc_device_mask r1, r0
249
250exit_selfrefresh_loop:
251	ldr	r2, [r0, #EMC_EMC_STATUS]
252	ands	r2, r2, r1
253	bne	exit_selfrefresh_loop
254
255	mov	r1, #0			@ unstall all transactions
256	str	r1, [r0, #EMC_REQ_CTRL]
257
258	mov32	r0, TEGRA_PMC_BASE
259	ldr	r0, [r0, #PMC_SCRATCH41]
260	ret	r0			@ jump to tegra_resume
261ENDPROC(tegra20_lp1_reset)
262
263/*
264 * tegra20_tear_down_core
265 *
266 * copied into and executed from IRAM
267 * puts memory in self-refresh for LP0 and LP1
268 */
269tegra20_tear_down_core:
270	bl	tegra20_sdram_self_refresh
271	bl	tegra20_switch_cpu_to_clk32k
272	b	tegra20_enter_sleep
273
274/*
275 * tegra20_switch_cpu_to_clk32k
276 *
277 * In LP0 and LP1 all PLLs will be turned off. Switch the CPU and system clock
278 * to the 32KHz clock.
279 */
280tegra20_switch_cpu_to_clk32k:
281	/*
282	 * start by switching to CLKM to safely disable PLLs, then switch to
283	 * CLKS.
284	 */
285	mov	r0, #(1 << 28)
286	str	r0, [r5, #CLK_RESET_SCLK_BURST]
287	str	r0, [r5, #CLK_RESET_CCLK_BURST]
288	mov	r0, #0
289	str	r0, [r5, #CLK_RESET_CCLK_DIVIDER]
290	str	r0, [r5, #CLK_RESET_SCLK_DIVIDER]
291
292	/* 2uS delay delay between changing SCLK and disabling PLLs */
293	mov32	r7, TEGRA_TMRUS_BASE
294	ldr	r1, [r7]
295	add	r1, r1, #2
296	wait_until r1, r7, r9
297
298	store_pll_state r0, r1, r5, CLK_RESET_PLLC_BASE, PLLC_STORE_MASK
299	store_pll_state r0, r1, r5, CLK_RESET_PLLM_BASE, PLLM_STORE_MASK
300	store_pll_state r0, r1, r5, CLK_RESET_PLLP_BASE, PLLP_STORE_MASK
301
302	/* disable PLLM, PLLP and PLLC */
303	ldr	r0, [r5, #CLK_RESET_PLLM_BASE]
304	bic	r0, r0, #(1 << 30)
305	str	r0, [r5, #CLK_RESET_PLLM_BASE]
306	ldr	r0, [r5, #CLK_RESET_PLLP_BASE]
307	bic	r0, r0, #(1 << 30)
308	str	r0, [r5, #CLK_RESET_PLLP_BASE]
309	ldr	r0, [r5, #CLK_RESET_PLLC_BASE]
310	bic	r0, r0, #(1 << 30)
311	str	r0, [r5, #CLK_RESET_PLLC_BASE]
312
313	/* switch to CLKS */
314	mov	r0, #0	/* brust policy = 32KHz */
315	str	r0, [r5, #CLK_RESET_SCLK_BURST]
316
317	ret	lr
318
319/*
320 * tegra20_enter_sleep
321 *
322 * uses flow controller to enter sleep state
323 * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
324 * executes from SDRAM with target state is LP2
325 */
326tegra20_enter_sleep:
327	mov32   r6, TEGRA_FLOW_CTRL_BASE
328
329	mov     r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
330	orr	r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
331	cpu_id	r1
332	cpu_to_halt_reg r1, r1
333	str	r0, [r6, r1]
334	dsb
335	ldr	r0, [r6, r1] /* memory barrier */
336
337halted:
338	dsb
339	wfe	/* CPU should be power gated here */
340	isb
341	b	halted
342
343/*
344 * tegra20_sdram_self_refresh
345 *
346 * called with MMU off and caches disabled
347 * puts sdram in self refresh
348 * must be executed from IRAM
349 */
350tegra20_sdram_self_refresh:
351	mov32	r1, TEGRA_EMC_BASE	@ r1 reserved for emc base addr
352
353	mov	r2, #3
354	str	r2, [r1, #EMC_REQ_CTRL]	@ stall incoming DRAM requests
355
356emcidle:
357	ldr	r2, [r1, #EMC_EMC_STATUS]
358	tst	r2, #4
359	beq	emcidle
360
361	mov	r2, #1
362	str	r2, [r1, #EMC_SELF_REF]
363
364	emc_device_mask r2, r1
365
366emcself:
367	ldr	r3, [r1, #EMC_EMC_STATUS]
368	and	r3, r3, r2
369	cmp	r3, r2
370	bne	emcself			@ loop until DDR in self-refresh
371
372	adr	r2, tegra20_sdram_pad_address
373	adr	r3, tegra20_sdram_pad_safe
374	adr	r4, tegra20_sdram_pad_save
375	mov	r5, #0
376
377	ldr	r6, tegra20_sdram_pad_size
378padsave:
379	ldr	r0, [r2, r5]		@ r0 is the addr in the pad_address
380
381	ldr	r1, [r0]
382	str	r1, [r4, r5]		@ save the content of the addr
383
384	ldr	r1, [r3, r5]
385	str	r1, [r0]		@ set the save val to the addr
386
387	add	r5, r5, #4
388	cmp	r6, r5
389	bne	padsave
390padsave_done:
391
392	mov32	r5, TEGRA_CLK_RESET_BASE
393	ldr	r0, [r5, #CLK_RESET_SCLK_BURST]
394	adr	r2, tegra20_sclk_save
395	str	r0, [r2]
396	dsb
397	ret	lr
398
399tegra20_sdram_pad_address:
400	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL
401	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL
402	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CLKCFGPADCTRL
403	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2COMPPADCTRL
404	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2VTTGENPADCTRL
405	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL2
406	.word	TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL2
407
408tegra20_sdram_pad_size:
409	.word	tegra20_sdram_pad_size - tegra20_sdram_pad_address
410
411tegra20_sdram_pad_safe:
412	.word	0x8
413	.word	0x8
414	.word	0x0
415	.word	0x8
416	.word	0x5500
417	.word	0x08080040
418	.word	0x0
419
420tegra20_sclk_save:
421	.word	0x0
422
423tegra20_sdram_pad_save:
424	.rept (tegra20_sdram_pad_size - tegra20_sdram_pad_address) / 4
425	.long	0
426	.endr
427
428tegra_pll_state:
429	.word	0x0
430
431	.ltorg
432/* dummy symbol for end of IRAM */
433	.align L1_CACHE_SHIFT
434	.globl tegra20_iram_end
435tegra20_iram_end:
436	b	.
437#endif
438