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