linux/arch/arm/mach-tegra/sleep-tegra20.S
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2010-2012, NVIDIA Corporation. All rights reserved.
   3 * Copyright (c) 2011, Google, Inc.
   4 *
   5 * Author: Colin Cross <ccross@android.com>
   6 *         Gary King <gking@nvidia.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify it
   9 * under the terms and conditions of the GNU General Public License,
  10 * version 2, as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope it will be useful, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15 * more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19 */
  20
  21#include <linux/linkage.h>
  22
  23#include <soc/tegra/flowctrl.h>
  24
  25#include <asm/assembler.h>
  26#include <asm/proc-fns.h>
  27#include <asm/cp15.h>
  28#include <asm/cache.h>
  29
  30#include "irammap.h"
  31#include "sleep.h"
  32
  33#define EMC_CFG                         0xc
  34#define EMC_ADR_CFG                     0x10
  35#define EMC_REFRESH                     0x70
  36#define EMC_NOP                         0xdc
  37#define EMC_SELF_REF                    0xe0
  38#define EMC_REQ_CTRL                    0x2b0
  39#define EMC_EMC_STATUS                  0x2b4
  40
  41#define CLK_RESET_CCLK_BURST            0x20
  42#define CLK_RESET_CCLK_DIVIDER          0x24
  43#define CLK_RESET_SCLK_BURST            0x28
  44#define CLK_RESET_SCLK_DIVIDER          0x2c
  45#define CLK_RESET_PLLC_BASE             0x80
  46#define CLK_RESET_PLLM_BASE             0x90
  47#define CLK_RESET_PLLP_BASE             0xa0
  48
  49#define APB_MISC_XM2CFGCPADCTRL         0x8c8
  50#define APB_MISC_XM2CFGDPADCTRL         0x8cc
  51#define APB_MISC_XM2CLKCFGPADCTRL       0x8d0
  52#define APB_MISC_XM2COMPPADCTRL         0x8d4
  53#define APB_MISC_XM2VTTGENPADCTRL       0x8d8
  54#define APB_MISC_XM2CFGCPADCTRL2        0x8e4
  55#define APB_MISC_XM2CFGDPADCTRL2        0x8e8
  56
  57.macro pll_enable, rd, r_car_base, pll_base
  58        ldr     \rd, [\r_car_base, #\pll_base]
  59        tst     \rd, #(1 << 30)
  60        orreq   \rd, \rd, #(1 << 30)
  61        streq   \rd, [\r_car_base, #\pll_base]
  62.endm
  63
  64.macro emc_device_mask, rd, base
  65        ldr     \rd, [\base, #EMC_ADR_CFG]
  66        tst     \rd, #(0x3 << 24)
  67        moveq   \rd, #(0x1 << 8)                @ just 1 device
  68        movne   \rd, #(0x3 << 8)                @ 2 devices
  69.endm
  70
  71#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP)
  72/*
  73 * tegra20_hotplug_shutdown(void)
  74 *
  75 * puts the current cpu in reset
  76 * should never return
  77 */
  78ENTRY(tegra20_hotplug_shutdown)
  79        /* Put this CPU down */
  80        cpu_id  r0
  81        bl      tegra20_cpu_shutdown
  82        ret     lr                      @ should never get here
  83ENDPROC(tegra20_hotplug_shutdown)
  84
  85/*
  86 * tegra20_cpu_shutdown(int cpu)
  87 *
  88 * r0 is cpu to reset
  89 *
  90 * puts the specified CPU in wait-for-event mode on the flow controller
  91 * and puts the CPU in reset
  92 * can be called on the current cpu or another cpu
  93 * if called on the current cpu, does not return
  94 * MUST NOT BE CALLED FOR CPU 0.
  95 *
  96 * corrupts r0-r3, r12
  97 */
  98ENTRY(tegra20_cpu_shutdown)
  99        cmp     r0, #0
 100        reteq   lr                      @ must not be called for CPU 0
 101        mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
 102        ldr     r2, =__tegra20_cpu1_resettable_status_offset
 103        mov     r12, #CPU_RESETTABLE
 104        strb    r12, [r1, r2]
 105
 106        cpu_to_halt_reg r1, r0
 107        ldr     r3, =TEGRA_FLOW_CTRL_VIRT
 108        mov     r2, #FLOW_CTRL_WAITEVENT | FLOW_CTRL_JTAG_RESUME
 109        str     r2, [r3, r1]            @ put flow controller in wait event mode
 110        ldr     r2, [r3, r1]
 111        isb
 112        dsb
 113        movw    r1, 0x1011
 114        mov     r1, r1, lsl r0
 115        ldr     r3, =TEGRA_CLK_RESET_VIRT
 116        str     r1, [r3, #0x340]        @ put slave CPU in reset
 117        isb
 118        dsb
 119        cpu_id  r3
 120        cmp     r3, r0
 121        beq     .
 122        ret     lr
 123ENDPROC(tegra20_cpu_shutdown)
 124#endif
 125
 126#ifdef CONFIG_PM_SLEEP
 127/*
 128 * tegra_pen_lock
 129 *
 130 * spinlock implementation with no atomic test-and-set and no coherence
 131 * using Peterson's algorithm on strongly-ordered registers
 132 * used to synchronize a cpu waking up from wfi with entering lp2 on idle
 133 *
 134 * The reference link of Peterson's algorithm:
 135 * http://en.wikipedia.org/wiki/Peterson's_algorithm
 136 *
 137 * SCRATCH37 = r1 = !turn (inverted from Peterson's algorithm)
 138 * on cpu 0:
 139 * r2 = flag[0] (in SCRATCH38)
 140 * r3 = flag[1] (in SCRATCH39)
 141 * on cpu1:
 142 * r2 = flag[1] (in SCRATCH39)
 143 * r3 = flag[0] (in SCRATCH38)
 144 *
 145 * must be called with MMU on
 146 * corrupts r0-r3, r12
 147 */
 148ENTRY(tegra_pen_lock)
 149        mov32   r3, TEGRA_PMC_VIRT
 150        cpu_id  r0
 151        add     r1, r3, #PMC_SCRATCH37
 152        cmp     r0, #0
 153        addeq   r2, r3, #PMC_SCRATCH38
 154        addeq   r3, r3, #PMC_SCRATCH39
 155        addne   r2, r3, #PMC_SCRATCH39
 156        addne   r3, r3, #PMC_SCRATCH38
 157
 158        mov     r12, #1
 159        str     r12, [r2]               @ flag[cpu] = 1
 160        dsb
 161        str     r12, [r1]               @ !turn = cpu
 1621:      dsb
 163        ldr     r12, [r3]
 164        cmp     r12, #1                 @ flag[!cpu] == 1?
 165        ldreq   r12, [r1]
 166        cmpeq   r12, r0                 @ !turn == cpu?
 167        beq     1b                      @ while !turn == cpu && flag[!cpu] == 1
 168
 169        ret     lr                      @ locked
 170ENDPROC(tegra_pen_lock)
 171
 172ENTRY(tegra_pen_unlock)
 173        dsb
 174        mov32   r3, TEGRA_PMC_VIRT
 175        cpu_id  r0
 176        cmp     r0, #0
 177        addeq   r2, r3, #PMC_SCRATCH38
 178        addne   r2, r3, #PMC_SCRATCH39
 179        mov     r12, #0
 180        str     r12, [r2]
 181        ret     lr
 182ENDPROC(tegra_pen_unlock)
 183
 184/*
 185 * tegra20_cpu_clear_resettable(void)
 186 *
 187 * Called to clear the "resettable soon" flag in IRAM variable when
 188 * it is expected that the secondary CPU will be idle soon.
 189 */
 190ENTRY(tegra20_cpu_clear_resettable)
 191        mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
 192        ldr     r2, =__tegra20_cpu1_resettable_status_offset
 193        mov     r12, #CPU_NOT_RESETTABLE
 194        strb    r12, [r1, r2]
 195        ret     lr
 196ENDPROC(tegra20_cpu_clear_resettable)
 197
 198/*
 199 * tegra20_cpu_set_resettable_soon(void)
 200 *
 201 * Called to set the "resettable soon" flag in IRAM variable when
 202 * it is expected that the secondary CPU will be idle soon.
 203 */
 204ENTRY(tegra20_cpu_set_resettable_soon)
 205        mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
 206        ldr     r2, =__tegra20_cpu1_resettable_status_offset
 207        mov     r12, #CPU_RESETTABLE_SOON
 208        strb    r12, [r1, r2]
 209        ret     lr
 210ENDPROC(tegra20_cpu_set_resettable_soon)
 211
 212/*
 213 * tegra20_cpu_is_resettable_soon(void)
 214 *
 215 * Returns true if the "resettable soon" flag in IRAM variable has been
 216 * set because it is expected that the secondary CPU will be idle soon.
 217 */
 218ENTRY(tegra20_cpu_is_resettable_soon)
 219        mov32   r1, TEGRA_IRAM_RESET_BASE_VIRT
 220        ldr     r2, =__tegra20_cpu1_resettable_status_offset
 221        ldrb    r12, [r1, r2]
 222        cmp     r12, #CPU_RESETTABLE_SOON
 223        moveq   r0, #1
 224        movne   r0, #0
 225        ret     lr
 226ENDPROC(tegra20_cpu_is_resettable_soon)
 227
 228/*
 229 * tegra20_sleep_core_finish(unsigned long v2p)
 230 *
 231 * Enters suspend in LP0 or LP1 by turning off the mmu and jumping to
 232 * tegra20_tear_down_core in IRAM
 233 */
 234ENTRY(tegra20_sleep_core_finish)
 235        mov     r4, r0
 236        /* Flush, disable the L1 data cache and exit SMP */
 237        mov     r0, #TEGRA_FLUSH_CACHE_ALL
 238        bl      tegra_disable_clean_inv_dcache
 239        mov     r0, r4
 240
 241        mov32   r3, tegra_shut_off_mmu
 242        add     r3, r3, r0
 243
 244        mov32   r0, tegra20_tear_down_core
 245        mov32   r1, tegra20_iram_start
 246        sub     r0, r0, r1
 247        mov32   r1, TEGRA_IRAM_LPx_RESUME_AREA
 248        add     r0, r0, r1
 249
 250        ret     r3
 251ENDPROC(tegra20_sleep_core_finish)
 252
 253/*
 254 * tegra20_sleep_cpu_secondary_finish(unsigned long v2p)
 255 *
 256 * Enters WFI on secondary CPU by exiting coherency.
 257 */
 258ENTRY(tegra20_sleep_cpu_secondary_finish)
 259        stmfd   sp!, {r4-r11, lr}
 260
 261        mrc     p15, 0, r11, c1, c0, 1  @ save actlr before exiting coherency
 262
 263        /* Flush and disable the L1 data cache */
 264        mov     r0, #TEGRA_FLUSH_CACHE_LOUIS
 265        bl      tegra_disable_clean_inv_dcache
 266
 267        mov32   r0, TEGRA_IRAM_RESET_BASE_VIRT
 268        ldr     r4, =__tegra20_cpu1_resettable_status_offset
 269        mov     r3, #CPU_RESETTABLE
 270        strb    r3, [r0, r4]
 271
 272        bl      tegra_cpu_do_idle
 273
 274        /*
 275         * cpu may be reset while in wfi, which will return through
 276         * tegra_resume to cpu_resume
 277         * or interrupt may wake wfi, which will return here
 278         * cpu state is unchanged - MMU is on, cache is on, coherency
 279         * is off, and the data cache is off
 280         *
 281         * r11 contains the original actlr
 282         */
 283
 284        bl      tegra_pen_lock
 285
 286        mov32   r0, TEGRA_IRAM_RESET_BASE_VIRT
 287        ldr     r4, =__tegra20_cpu1_resettable_status_offset
 288        mov     r3, #CPU_NOT_RESETTABLE
 289        strb    r3, [r0, r4]
 290
 291        bl      tegra_pen_unlock
 292
 293        /* Re-enable the data cache */
 294        mrc     p15, 0, r10, c1, c0, 0
 295        orr     r10, r10, #CR_C
 296        mcr     p15, 0, r10, c1, c0, 0
 297        isb
 298
 299        mcr     p15, 0, r11, c1, c0, 1  @ reenable coherency
 300
 301        /* Invalidate the TLBs & BTAC */
 302        mov     r1, #0
 303        mcr     p15, 0, r1, c8, c3, 0   @ invalidate shared TLBs
 304        mcr     p15, 0, r1, c7, c1, 6   @ invalidate shared BTAC
 305        dsb
 306        isb
 307
 308        /* the cpu was running with coherency disabled,
 309         * caches may be out of date */
 310        bl      v7_flush_kern_cache_louis
 311
 312        ldmfd   sp!, {r4 - r11, pc}
 313ENDPROC(tegra20_sleep_cpu_secondary_finish)
 314
 315/*
 316 * tegra20_tear_down_cpu
 317 *
 318 * Switches the CPU cluster to PLL-P and enters sleep.
 319 */
 320ENTRY(tegra20_tear_down_cpu)
 321        bl      tegra_switch_cpu_to_pllp
 322        b       tegra20_enter_sleep
 323ENDPROC(tegra20_tear_down_cpu)
 324
 325/* START OF ROUTINES COPIED TO IRAM */
 326        .align L1_CACHE_SHIFT
 327        .globl tegra20_iram_start
 328tegra20_iram_start:
 329
 330/*
 331 * tegra20_lp1_reset
 332 *
 333 * reset vector for LP1 restore; copied into IRAM during suspend.
 334 * Brings the system back up to a safe staring point (SDRAM out of
 335 * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP,
 336 * system clock running on the same PLL that it suspended at), and
 337 * jumps to tegra_resume to restore virtual addressing and PLLX.
 338 * The physical address of tegra_resume expected to be stored in
 339 * PMC_SCRATCH41.
 340 *
 341 * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_LPx_RESUME_AREA.
 342 */
 343ENTRY(tegra20_lp1_reset)
 344        /*
 345         * The CPU and system bus are running at 32KHz and executing from
 346         * IRAM when this code is executed; immediately switch to CLKM and
 347         * enable PLLM, PLLP, PLLC.
 348         */
 349        mov32   r0, TEGRA_CLK_RESET_BASE
 350
 351        mov     r1, #(1 << 28)
 352        str     r1, [r0, #CLK_RESET_SCLK_BURST]
 353        str     r1, [r0, #CLK_RESET_CCLK_BURST]
 354        mov     r1, #0
 355        str     r1, [r0, #CLK_RESET_CCLK_DIVIDER]
 356        str     r1, [r0, #CLK_RESET_SCLK_DIVIDER]
 357
 358        pll_enable r1, r0, CLK_RESET_PLLM_BASE
 359        pll_enable r1, r0, CLK_RESET_PLLP_BASE
 360        pll_enable r1, r0, CLK_RESET_PLLC_BASE
 361
 362        adr     r2, tegra20_sdram_pad_address
 363        adr     r4, tegra20_sdram_pad_save
 364        mov     r5, #0
 365
 366        ldr     r6, tegra20_sdram_pad_size
 367padload:
 368        ldr     r7, [r2, r5]            @ r7 is the addr in the pad_address
 369
 370        ldr     r1, [r4, r5]
 371        str     r1, [r7]                @ restore the value in pad_save
 372
 373        add     r5, r5, #4
 374        cmp     r6, r5
 375        bne     padload
 376
 377padload_done:
 378        /* 255uS delay for PLL stabilization */
 379        mov32   r7, TEGRA_TMRUS_BASE
 380        ldr     r1, [r7]
 381        add     r1, r1, #0xff
 382        wait_until r1, r7, r9
 383
 384        adr     r4, tegra20_sclk_save
 385        ldr     r4, [r4]
 386        str     r4, [r0, #CLK_RESET_SCLK_BURST]
 387        mov32   r4, ((1 << 28) | (4))   @ burst policy is PLLP
 388        str     r4, [r0, #CLK_RESET_CCLK_BURST]
 389
 390        mov32   r0, TEGRA_EMC_BASE
 391        ldr     r1, [r0, #EMC_CFG]
 392        bic     r1, r1, #(1 << 31)      @ disable DRAM_CLK_STOP
 393        str     r1, [r0, #EMC_CFG]
 394
 395        mov     r1, #0
 396        str     r1, [r0, #EMC_SELF_REF] @ take DRAM out of self refresh
 397        mov     r1, #1
 398        str     r1, [r0, #EMC_NOP]
 399        str     r1, [r0, #EMC_NOP]
 400        str     r1, [r0, #EMC_REFRESH]
 401
 402        emc_device_mask r1, r0
 403
 404exit_selfrefresh_loop:
 405        ldr     r2, [r0, #EMC_EMC_STATUS]
 406        ands    r2, r2, r1
 407        bne     exit_selfrefresh_loop
 408
 409        mov     r1, #0                  @ unstall all transactions
 410        str     r1, [r0, #EMC_REQ_CTRL]
 411
 412        mov32   r0, TEGRA_PMC_BASE
 413        ldr     r0, [r0, #PMC_SCRATCH41]
 414        ret     r0                      @ jump to tegra_resume
 415ENDPROC(tegra20_lp1_reset)
 416
 417/*
 418 * tegra20_tear_down_core
 419 *
 420 * copied into and executed from IRAM
 421 * puts memory in self-refresh for LP0 and LP1
 422 */
 423tegra20_tear_down_core:
 424        bl      tegra20_sdram_self_refresh
 425        bl      tegra20_switch_cpu_to_clk32k
 426        b       tegra20_enter_sleep
 427
 428/*
 429 * tegra20_switch_cpu_to_clk32k
 430 *
 431 * In LP0 and LP1 all PLLs will be turned off. Switch the CPU and system clock
 432 * to the 32KHz clock.
 433 */
 434tegra20_switch_cpu_to_clk32k:
 435        /*
 436         * start by switching to CLKM to safely disable PLLs, then switch to
 437         * CLKS.
 438         */
 439        mov     r0, #(1 << 28)
 440        str     r0, [r5, #CLK_RESET_SCLK_BURST]
 441        str     r0, [r5, #CLK_RESET_CCLK_BURST]
 442        mov     r0, #0
 443        str     r0, [r5, #CLK_RESET_CCLK_DIVIDER]
 444        str     r0, [r5, #CLK_RESET_SCLK_DIVIDER]
 445
 446        /* 2uS delay delay between changing SCLK and disabling PLLs */
 447        mov32   r7, TEGRA_TMRUS_BASE
 448        ldr     r1, [r7]
 449        add     r1, r1, #2
 450        wait_until r1, r7, r9
 451
 452        /* disable PLLM, PLLP and PLLC */
 453        ldr     r0, [r5, #CLK_RESET_PLLM_BASE]
 454        bic     r0, r0, #(1 << 30)
 455        str     r0, [r5, #CLK_RESET_PLLM_BASE]
 456        ldr     r0, [r5, #CLK_RESET_PLLP_BASE]
 457        bic     r0, r0, #(1 << 30)
 458        str     r0, [r5, #CLK_RESET_PLLP_BASE]
 459        ldr     r0, [r5, #CLK_RESET_PLLC_BASE]
 460        bic     r0, r0, #(1 << 30)
 461        str     r0, [r5, #CLK_RESET_PLLC_BASE]
 462
 463        /* switch to CLKS */
 464        mov     r0, #0  /* brust policy = 32KHz */
 465        str     r0, [r5, #CLK_RESET_SCLK_BURST]
 466
 467        ret     lr
 468
 469/*
 470 * tegra20_enter_sleep
 471 *
 472 * uses flow controller to enter sleep state
 473 * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1
 474 * executes from SDRAM with target state is LP2
 475 */
 476tegra20_enter_sleep:
 477        mov32   r6, TEGRA_FLOW_CTRL_BASE
 478
 479        mov     r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT
 480        orr     r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ
 481        cpu_id  r1
 482        cpu_to_halt_reg r1, r1
 483        str     r0, [r6, r1]
 484        dsb
 485        ldr     r0, [r6, r1] /* memory barrier */
 486
 487halted:
 488        dsb
 489        wfe     /* CPU should be power gated here */
 490        isb
 491        b       halted
 492
 493/*
 494 * tegra20_sdram_self_refresh
 495 *
 496 * called with MMU off and caches disabled
 497 * puts sdram in self refresh
 498 * must be executed from IRAM
 499 */
 500tegra20_sdram_self_refresh:
 501        mov32   r1, TEGRA_EMC_BASE      @ r1 reserved for emc base addr
 502
 503        mov     r2, #3
 504        str     r2, [r1, #EMC_REQ_CTRL] @ stall incoming DRAM requests
 505
 506emcidle:
 507        ldr     r2, [r1, #EMC_EMC_STATUS]
 508        tst     r2, #4
 509        beq     emcidle
 510
 511        mov     r2, #1
 512        str     r2, [r1, #EMC_SELF_REF]
 513
 514        emc_device_mask r2, r1
 515
 516emcself:
 517        ldr     r3, [r1, #EMC_EMC_STATUS]
 518        and     r3, r3, r2
 519        cmp     r3, r2
 520        bne     emcself                 @ loop until DDR in self-refresh
 521
 522        adr     r2, tegra20_sdram_pad_address
 523        adr     r3, tegra20_sdram_pad_safe
 524        adr     r4, tegra20_sdram_pad_save
 525        mov     r5, #0
 526
 527        ldr     r6, tegra20_sdram_pad_size
 528padsave:
 529        ldr     r0, [r2, r5]            @ r0 is the addr in the pad_address
 530
 531        ldr     r1, [r0]
 532        str     r1, [r4, r5]            @ save the content of the addr
 533
 534        ldr     r1, [r3, r5]
 535        str     r1, [r0]                @ set the save val to the addr
 536
 537        add     r5, r5, #4
 538        cmp     r6, r5
 539        bne     padsave
 540padsave_done:
 541
 542        mov32   r5, TEGRA_CLK_RESET_BASE
 543        ldr     r0, [r5, #CLK_RESET_SCLK_BURST]
 544        adr     r2, tegra20_sclk_save
 545        str     r0, [r2]
 546        dsb
 547        ret     lr
 548
 549tegra20_sdram_pad_address:
 550        .word   TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL
 551        .word   TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL
 552        .word   TEGRA_APB_MISC_BASE + APB_MISC_XM2CLKCFGPADCTRL
 553        .word   TEGRA_APB_MISC_BASE + APB_MISC_XM2COMPPADCTRL
 554        .word   TEGRA_APB_MISC_BASE + APB_MISC_XM2VTTGENPADCTRL
 555        .word   TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGCPADCTRL2
 556        .word   TEGRA_APB_MISC_BASE + APB_MISC_XM2CFGDPADCTRL2
 557
 558tegra20_sdram_pad_size:
 559        .word   tegra20_sdram_pad_size - tegra20_sdram_pad_address
 560
 561tegra20_sdram_pad_safe:
 562        .word   0x8
 563        .word   0x8
 564        .word   0x0
 565        .word   0x8
 566        .word   0x5500
 567        .word   0x08080040
 568        .word   0x0
 569
 570tegra20_sclk_save:
 571        .word   0x0
 572
 573tegra20_sdram_pad_save:
 574        .rept (tegra20_sdram_pad_size - tegra20_sdram_pad_address) / 4
 575        .long   0
 576        .endr
 577
 578        .ltorg
 579/* dummy symbol for end of IRAM */
 580        .align L1_CACHE_SHIFT
 581        .globl tegra20_iram_end
 582tegra20_iram_end:
 583        b       .
 584#endif
 585