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

source code of linux/arch/arm/mach-tegra/sleep-tegra20.S