Merge branch 'address-masking'
[linux-2.6-microblaze.git] / arch / arm / mach-tegra / sleep-tegra20.S
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]
75 1:
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  */
92 ENTRY(tegra20_hotplug_shutdown)
93         /* Put this CPU down */
94         cpu_id  r0
95         bl      tegra20_cpu_shutdown
96         ret     lr                      @ should never get here
97 ENDPROC(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  */
112 ENTRY(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
133 ENDPROC(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  */
143 ENTRY(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
160 ENDPROC(tegra20_sleep_core_finish)
161
162 /*
163  * tegra20_tear_down_cpu
164  *
165  * Switches the CPU cluster to PLL-P and enters sleep.
166  */
167 ENTRY(tegra20_tear_down_cpu)
168         bl      tegra_switch_cpu_to_pllp
169         b       tegra20_enter_sleep
170 ENDPROC(tegra20_tear_down_cpu)
171
172 /* START OF ROUTINES COPIED TO IRAM */
173         .align L1_CACHE_SHIFT
174         .globl tegra20_iram_start
175 tegra20_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  */
190 ENTRY(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
214 padload:
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
224 padload_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
250 exit_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
261 ENDPROC(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  */
269 tegra20_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  */
280 tegra20_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  */
326 tegra20_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
337 halted:
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  */
350 tegra20_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
356 emcidle:
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
366 emcself:
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
378 padsave:
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
390 padsave_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
399 tegra20_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
408 tegra20_sdram_pad_size:
409         .word   tegra20_sdram_pad_size - tegra20_sdram_pad_address
410
411 tegra20_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
420 tegra20_sclk_save:
421         .word   0x0
422
423 tegra20_sdram_pad_save:
424         .rept (tegra20_sdram_pad_size - tegra20_sdram_pad_address) / 4
425         .long   0
426         .endr
427
428 tegra_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
435 tegra20_iram_end:
436         b       .
437 #endif