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