~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-tegra/sleep-tegra20.S

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php