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