1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * Copyright (c) 2010-2012, NVIDIA Corporation 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 << 47 #define PLLM_STORE_MASK (1 << 48 #define PLLP_STORE_MASK (1 << 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, p 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, t 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) 82 movne \rd, #(0x3 << 8) 83 .endm 84 85 #if defined(CONFIG_HOTPLUG_CPU) || defined(CON 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 @ shou 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 mo 105 * and puts the CPU in reset 106 * can be called on the current cpu or another 107 * if called on the current cpu, does not retu 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 115 116 cpu_to_halt_reg r1, r0 117 ldr r3, =TEGRA_FLOW_CTRL_VIRT 118 mov r2, #FLOW_CTRL_WAITEVENT | FLO 119 str r2, [r3, r1] @ put 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 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 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 an 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 enter 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 I 181 * Brings the system back up to a safe staring 182 * self-refresh, PLLC, PLLM and PLLP reenabled 183 * system clock running on the same PLL that i 184 * jumps to tegra_resume to restore virtual ad 185 * The physical address of tegra_resume expect 186 * PMC_SCRATCH41. 187 * 188 * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRA 189 */ 190 ENTRY(tegra20_lp1_reset) 191 /* 192 * The CPU and system bus are running 193 * IRAM when this code is executed; im 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_DIVID 203 str r1, [r0, #CLK_RESET_SCLK_DIVID 204 205 pll_enable r1, r0, CLK_RESET_PLLM_BASE 206 pll_enable r1, r0, CLK_RESET_PLLP_BASE 207 pll_enable r1, r0, CLK_RESET_PLLC_BASE 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 i 216 217 ldr r1, [r4, r5] 218 str r1, [r7] @ rest 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)) @ burs 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) @ disa 240 str r1, [r0, #EMC_CFG] 241 242 mov r1, #0 243 str r1, [r0, #EMC_SELF_REF] @ take 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 @ unst 256 str r1, [r0, #EMC_REQ_CTRL] 257 258 mov32 r0, TEGRA_PMC_BASE 259 ldr r0, [r0, #PMC_SCRATCH41] 260 ret r0 @ jump 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. 278 * to the 32KHz clock. 279 */ 280 tegra20_switch_cpu_to_clk32k: 281 /* 282 * start by switching to CLKM to safel 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_DIVID 290 str r0, [r5, #CLK_RESET_SCLK_DIVID 291 292 /* 2uS delay delay between changing SC 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_ 299 store_pll_state r0, r1, r5, CLK_RESET_ 300 store_pll_state r0, r1, r5, CLK_RESET_ 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 = 32KH 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 selfrefres 324 * executes from SDRAM with target state is LP 325 */ 326 tegra20_enter_sleep: 327 mov32 r6, TEGRA_FLOW_CTRL_BASE 328 329 mov r0, #FLOW_CTRL_WAIT_FOR_INTERR 330 orr r0, r0, #FLOW_CTRL_HALT_CPU_IR 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 h 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 r 352 353 mov r2, #3 354 str r2, [r1, #EMC_REQ_CTRL] @ stal 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 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 i 380 381 ldr r1, [r0] 382 str r1, [r4, r5] @ save 383 384 ldr r1, [r3, r5] 385 str r1, [r0] @ set 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 401 .word TEGRA_APB_MISC_BASE + APB_MISC 402 .word TEGRA_APB_MISC_BASE + APB_MISC 403 .word TEGRA_APB_MISC_BASE + APB_MISC 404 .word TEGRA_APB_MISC_BASE + APB_MISC 405 .word TEGRA_APB_MISC_BASE + APB_MISC 406 .word TEGRA_APB_MISC_BASE + APB_MISC 407 408 tegra20_sdram_pad_size: 409 .word tegra20_sdram_pad_size - tegra 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 - tegra2 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.