Merge tag 'drm-msm-next-2021-02-07' of https://gitlab.freedesktop.org/drm/msm into...
[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 .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  */
67 ENTRY(tegra20_hotplug_shutdown)
68         /* Put this CPU down */
69         cpu_id  r0
70         bl      tegra20_cpu_shutdown
71         ret     lr                      @ should never get here
72 ENDPROC(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  */
87 ENTRY(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
108 ENDPROC(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  */
118 ENTRY(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
135 ENDPROC(tegra20_sleep_core_finish)
136
137 /*
138  * tegra20_tear_down_cpu
139  *
140  * Switches the CPU cluster to PLL-P and enters sleep.
141  */
142 ENTRY(tegra20_tear_down_cpu)
143         bl      tegra_switch_cpu_to_pllp
144         b       tegra20_enter_sleep
145 ENDPROC(tegra20_tear_down_cpu)
146
147 /* START OF ROUTINES COPIED TO IRAM */
148         .align L1_CACHE_SHIFT
149         .globl tegra20_iram_start
150 tegra20_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  */
165 ENTRY(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
189 padload:
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
199 padload_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
225 exit_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
236 ENDPROC(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  */
244 tegra20_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  */
255 tegra20_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  */
297 tegra20_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
308 halted:
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  */
321 tegra20_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
327 emcidle:
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
337 emcself:
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
349 padsave:
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
361 padsave_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
370 tegra20_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
379 tegra20_sdram_pad_size:
380         .word   tegra20_sdram_pad_size - tegra20_sdram_pad_address
381
382 tegra20_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
391 tegra20_sclk_save:
392         .word   0x0
393
394 tegra20_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
403 tegra20_iram_end:
404         b       .
405 #endif