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