/* * arch/arm/mach-tegra/include/mach/sleep-t3.S * * Copyright (c) 2010-2012, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "asm_macros.h" #include "sleep.h" #include "clock.h" #define EMC_CFG 0xc #define EMC_ADR_CFG 0x10 #define EMC_TIMING_CONTROL 0x28 #define EMC_REFRESH 0x70 #define EMC_NOP 0xdc #define EMC_SELF_REF 0xe0 #define EMC_MRW 0xe8 #define EMC_REQ_CTRL 0x2b0 #define EMC_EMC_STATUS 0x2b4 #define EMC_FBIO_CFG5 0x104 #define EMC_AUTO_CAL_CONFIG 0x2a4 #define EMC_AUTO_CAL_INTERVAL 0x2a8 #define EMC_AUTO_CAL_STATUS 0x2ac #define EMC_CFG_DIG_DLL 0x2bc #define EMC_ZCAL_INTERVAL 0x2e0 #define EMC_ZQ_CAL 0x2ec #define EMC_XM2VTTGENPADCTRL 0x310 #define EMC_XM2VTTGENPADCTRL2 0x314 #define PMC_CTRL 0x0 #define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */ #define PMC_PWRGATE_TOGGLE 0x30 #define PMC_REMOVE_CLAMPING_CMD 0x34 #define PMC_PWRGATE_STATUS 0x38 #define PMC_PWRGATE_PARTID_L2C (0x5) #define PMC_IO_DPD_REQ 0x1b8 #define PMC_IO_DPD_STATUS 0x1bc #define PMC_SCRATCH1_ECO 0x264 #define CLK_RESET_CCLK_BURST 0x20 #define CLK_RESET_CCLK_DIVIDER 0x24 #define CLK_RESET_SCLK_BURST 0x28 #define CLK_RESET_SCLK_DIVIDER 0x2c #define CLK_RESET_PLLC_BASE 0x80 #define CLK_RESET_PLLM_BASE 0x90 #define CLK_RESET_PLLP_BASE 0xa0 #define CLK_RESET_PLLA_BASE 0xb0 #define CLK_RESET_PLLX_BASE 0xe0 #define CLK_RESET_PLLC_MISC 0x8c #define CLK_RESET_PLLM_MISC 0x9c #define CLK_RESET_PLLP_MISC 0xac #define CLK_RESET_PLLA_MISC 0xbc #define CLK_RESET_PLLX_MISC 0xe4 #if !defined(CONFIG_ARCH_TEGRA_3x_SOC) #define CLK_RESET_PLLX_MISC3 0x518 #define CLK_RESET_PLLM_MISC_IDDQ 5 #define CLK_RESET_PLLC_MISC_IDDQ 26 #define CLK_RESET_PLLX_MISC3_IDDQ 3 #endif #define CLK_RESET_PLLP_OUTA 0xa4 #define CLK_RESET_PLLP_OUTB 0xa8 #define PMC_PLLP_WB0_OVERRIDE 0xf8 #define PMC_PLLM_WB0_OVERRIDE 0x1dc #define CLK_RESET_CLK_SOURCE_MSELECT 0x3b4 #define CLK_RESET_CLK_ENB_H_SET 0x328 #define CLK_RESET_CLK_ENB_H_CLR 0x32c #define CLK_RESET_CLK_RST_DEV_H_SET 0x308 #define CLK_RESET_CLK_RST_DEV_H_CLR 0x30c #define I2C_CNFG 0x0 #define I2C_ADDR0 0x4 #define I2C_DATA1 0xc #define I2C_DATA2 0x10 #define I2C_STATUS 0x1c #define MSELECT_CLKM (0x3 << 30) #if USE_PLL_LOCK_BITS #define LOCK_DELAY PLL_POST_LOCK_DELAY #else #define LOCK_DELAY 0xff /* 255uS delay for PLL stabilization */ #endif #define USE_PLLP_ON_SLEEP_ENTRY 0 .macro emc_device_mask, rd, base ldr \rd, [\base, #EMC_ADR_CFG] tst \rd, #0x1 moveq \rd, #(0x1<<8) @ just 1 device movne \rd, #(0x3<<8) @ 2 devices .endm .macro emc_timing_update, rd, base mov \rd, #1 str \rd, [\base, #EMC_TIMING_CONTROL] 1001: ldr \rd, [\base, #EMC_EMC_STATUS] tst \rd, #(0x1<<23) @ wait until EMC_STATUS_TIMING_UPDATE_STALLED is clear bne 1001b .endm #ifdef CONFIG_HOTPLUG_CPU /* * tegra3_hotplug_shutdown(void) * * Powergates the current CPU. * Should never return. */ ENTRY(tegra3_hotplug_shutdown) mov r6, lr bl tegra_cpu_exit_coherency /* Powergate this CPU. */ mov r0, #TEGRA_POWER_HOTPLUG_SHUTDOWN bl tegra3_cpu_reset mov pc, r6 @ should never get here ENDPROC(tegra3_hotplug_shutdown) #endif #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) /* * tegra3_cpu_reset(unsigned long flags) * * Puts the current CPU in wait-for-event mode on the flow controller * and powergates it -- flags (in R0) indicate the request type. * Must never be called for CPU 0. * * corrupts r0-r4, r12 */ ENTRY(tegra3_cpu_reset) cpu_id r3 #ifndef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE cmp r3, #0 moveq pc, lr @ Must never be called for CPU 0 #endif mov32 r12, TEGRA_FLOW_CTRL_VIRT cpu_to_csr_reg r1, r3 add r1, r1, r12 @ virtual CSR address for this CPU cpu_to_halt_reg r2, r3 add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU /* Clear this CPU's "event" and "interrupt" flags and power gate it when halting but not before it is in the "WFE" state. */ movw r12, FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | FLOW_CTRL_CSR_ENABLE #if defined(CONFIG_ARCH_TEGRA_11x_SOC) mov r4, #(1 << 8) @ wfi bitmap #else mov r4, #(1 << 4) @ wfe bitmap #endif orr r12, r12, r4, lsl r3 str r12, [r1] /* Halt this CPU. */ mov r3, #0x400 delay_1: subs r3, r3, #1 @ delay as a part of wfe war. bge delay_1; cpsid a @ disable imprecise aborts. ldr r3, [r1] @ read CSR str r3, [r1] @ clear CSR tst r0, #TEGRA_POWER_HOTPLUG_SHUTDOWN #ifdef CONFIG_ARCH_TEGRA_HAS_SYMMETRIC_CPU_PWR_GATE mov r3, #FLOW_CTRL_WAITEVENT orreq r3, r3, #FLOW_CTRL_HALT_GIC_IRQ orreq r3, r3, #FLOW_CTRL_HALT_GIC_FIQ #else moveq r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT @ For LP2 movne r3, #FLOW_CTRL_WAITEVENT @ For hotplug #endif str r3, [r2] ldr r0, [r2] b wfe_war __cpu_reset_again: dsb .align 5 #if defined(CONFIG_ARCH_TEGRA_11x_SOC) wfi @ CPU should be power gated here #else wfe @ CPU should be power gated here #endif wfe_war: b __cpu_reset_again /* 38 nop's, which fills reset of wfe cache line and 4 more cachelines with nop*/ .rept 38 nop .endr b . @ should never get here ENDPROC(tegra3_cpu_reset) #endif #ifdef CONFIG_PM_SLEEP /* * tegra3_sleep_core_finish(unsigned long int) * * enters suspend in LP0 or LP1 by turning off the mmu and jumping to * tegra3_tear_down_core in IRAM */ ENTRY(tegra3_sleep_core_finish) #if defined(CONFIG_ARCH_TEGRA_11x_SOC) mov r4, r0 bl tegra_flush_cache mov r0, r4 #endif bl tegra_cpu_exit_coherency /* preload all the address literals that are needed for the * CPU power-gating process, to avoid loads from SDRAM (which are * not supported once SDRAM is put into self-refresh. * LP0 / LP1 use physical address, since the MMU needs to be * disabled before putting SDRAM into self-refresh to avoid * memory access due to page table walks */ mov32 r4, TEGRA_PMC_BASE mov32 r5, TEGRA_CLK_RESET_BASE mov32 r6, TEGRA_FLOW_CTRL_BASE mov32 r7, TEGRA_TMRUS_BASE mov32 r1, tegra3_tear_down_core mov32 r2, tegra3_iram_start sub r1, r1, r2 mov32 r2, TEGRA_IRAM_CODE_AREA add r1, r1, r2 b tegra_turn_off_mmu ENDPROC(tegra3_sleep_core_finish) /* * tegra3_sleep_cpu_secondary_finish(unsigned long v2p) * * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU. */ ENTRY(tegra3_sleep_cpu_secondary_finish) mov r6, lr bl tegra_flush_l1_cache bl tegra_cpu_exit_coherency /* Powergate this CPU. */ mov r0, #0 @ power mode flags (!hotplug) bl tegra3_cpu_reset mov r0, #1 @ never return here mov pc, r6 ENDPROC(tegra3_sleep_cpu_secondary_finish) /* * tegra3_tear_down_cpu * * Switches the CPU cluster to PLL-P and enters sleep. */ ENTRY(tegra3_tear_down_cpu) mov32 r4, TEGRA_PMC_BASE mov32 r5, TEGRA_CLK_RESET_BASE mov32 r6, TEGRA_FLOW_CTRL_BASE mov32 r7, TEGRA_TMRUS_BASE #if USE_PLLP_ON_SLEEP_ENTRY bl tegra_cpu_pllp #endif b tegra3_enter_sleep ENDPROC(tegra3_tear_down_cpu) /* START OF ROUTINES COPIED TO IRAM */ .align L1_CACHE_SHIFT .globl tegra3_iram_start tegra3_iram_start: /* * tegra3_lp1_reset * * reset vector for LP1 restore; copied into IRAM during suspend. * brings the system back up to a safe starting point (SDRAM out of * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLP, * system clock running on the same PLL that it suspended at), and * jumps to tegra_lp2_startup to restore PLLX and virtual addressing. * physical address of tegra_lp2_startup expected to be stored in * PMC_SCRATCH41 * * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_CODE_AREA AND MUST BE FIRST. */ .macro pll_enable, rd, car, base, misc ldr \rd, [\car, #\base] tst \rd, #(1<<30) orreq \rd, \rd, #(1<<30) streq \rd, [\car, #\base] #if USE_PLL_LOCK_BITS .if \misc ldr \rd, [\car, #\misc] bic \rd, \rd, #(1<<18) str \rd, [\car, #\misc] ldr \rd, [\car, #\misc] ldr \rd, [\car, #\misc] orr \rd, \rd, #(1<<18) str \rd, [\car, #\misc] .endif #endif .endm .macro pll_locked, rd, car, base #if USE_PLL_LOCK_BITS 1: ldr \rd, [\car, #\base] tst \rd, #(1<<27) beq 1b #endif .endm .macro pll_iddq_exit, rd, car, iddq, iddq_bit ldr \rd, [\car, #\iddq] bic \rd, \rd, #(1<<\iddq_bit) str \rd, [\car, #\iddq] .endm .macro pll_iddq_entry, rd, car, iddq, iddq_bit ldr \rd, [\car, #\iddq] orr \rd, \rd, #(1<<\iddq_bit) str \rd, [\car, #\iddq] .endm ENTRY(tegra3_lp1_reset) /* the CPU and system bus are running at 32KHz and executing from * IRAM when this code is executed; immediately switch to CLKM and * enable PLLP, PLLM, PLLC, and PLLX. */ mov32 r0, TEGRA_CLK_RESET_BASE #ifndef CONFIG_TRUSTED_FOUNDATIONS /* secure code handles 32KHz to CLKM/OSC clock switch */ mov r1, #(1<<28) str r1, [r0, #CLK_RESET_SCLK_BURST] str r1, [r0, #CLK_RESET_CCLK_BURST] mov r1, #0 str r1, [r0, #CLK_RESET_SCLK_DIVIDER] str r1, [r0, #CLK_RESET_CCLK_DIVIDER] #endif #if defined(CONFIG_ARCH_TEGRA_3x_SOC) /* enable PLLM via PMC */ mov32 r2, TEGRA_PMC_BASE ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE] orr r1, r1, #(1<<12) str r1, [r2, #PMC_PLLP_WB0_OVERRIDE] pll_enable r1, r0, CLK_RESET_PLLM_BASE, CLK_RESET_PLLM_MISC pll_enable r1, r0, CLK_RESET_PLLC_BASE, CLK_RESET_PLLC_MISC pll_enable r1, r0, CLK_RESET_PLLX_BASE, CLK_RESET_PLLX_MISC #else pll_iddq_exit r1, r0, CLK_RESET_PLLM_MISC, CLK_RESET_PLLM_MISC_IDDQ pll_iddq_exit r1, r0, CLK_RESET_PLLC_MISC, CLK_RESET_PLLC_MISC_IDDQ pll_iddq_exit r1, r0, CLK_RESET_PLLX_MISC3, CLK_RESET_PLLX_MISC3_IDDQ mov32 r7, TEGRA_TMRUS_BASE ldr r1, [r7] add r1, r1, #2 wait_until r1, r7, r3 /* enable PLLM via PMC */ mov32 r2, TEGRA_PMC_BASE ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE] orr r1, r1, #(1<<12) str r1, [r2, #PMC_PLLP_WB0_OVERRIDE] pll_enable r1, r0, CLK_RESET_PLLM_BASE, 0 pll_enable r1, r0, CLK_RESET_PLLC_BASE, 0 pll_enable r1, r0, CLK_RESET_PLLX_BASE, 0 #endif pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC pll_locked r1, r0, CLK_RESET_PLLM_BASE pll_locked r1, r0, CLK_RESET_PLLP_BASE pll_locked r1, r0, CLK_RESET_PLLC_BASE pll_locked r1, r0, CLK_RESET_PLLX_BASE mov32 r7, TEGRA_TMRUS_BASE ldr r1, [r7] add r1, r1, #LOCK_DELAY wait_until r1, r7, r3 add r5, pc, #tegra3_sdram_pad_save-(.+8) @ r5 reserved for pad base ldr r4, [r5, #0x18] str r4, [r0, #CLK_RESET_CLK_SOURCE_MSELECT] ldr r4, [r5, #0x1C] str r4, [r0, #CLK_RESET_SCLK_BURST] #if defined(CONFIG_ARCH_TEGRA_3x_SOC) mov32 r4, ((1<<28) | (8)) @ burst policy is PLLX str r4, [r0, #CLK_RESET_CCLK_BURST] #endif #ifdef CONFIG_TEGRA_LP1_950 lp1_voltset: /* Restore the Core voltage to high on LP1 resume */ /* Reset(Enable/Disable) the DVC-I2C Controller*/ mov r1, #(1 << 15) str r1, [r0, #CLK_RESET_CLK_RST_DEV_H_SET] /* Wait for 2us */ mov32 r7, TEGRA_TMRUS_BASE wait_for_us r1, r7, r9 add r1, r1, #2 wait_until r1, r7, r9 mov r1, #(1 << 15) str r1, [r0, #CLK_RESET_CLK_RST_DEV_H_CLR] /* Enable the DVC-I2C Controller */ mov r1, #(1 << 15) str r1, [r0, #CLK_RESET_CLK_ENB_H_SET] /* Same I2C transaction protocol as suspend */ ldr r1, lp1_register_pmuslave_addr cmp r1, #0 beq lp1_voltskip_resume ldr r4, lp1_register_i2c_base_addr str r1, [r4, #I2C_ADDR0] mov32 r1, 0x2 str r1, [r4, #I2C_CNFG] ldr r1, lp1_register_core_highvolt str r1, [r4, #I2C_DATA1] mov32 r1, 0 str r1, [r4, #I2C_DATA2] mov32 r1, 0xA02 str r1, [r4, #I2C_CNFG] wait_for_us r1, r7, r9 mov32 r3, 0x7D0 /* Wait for 2ms and try transaction again */ add r0, r1, r3 loop_i2c_status_resume: add r1, r1, #0xFA /* Check status every 250us */ wait_until r1, r7, r9 cmp r0, r1 beq lp1_voltset ldr r3, [r4, #I2C_STATUS] cmp r3, #0 bne loop_i2c_status_resume lp1_voltskip_resume: /* Disable the DVC-I2C Controller */ mov r0, #(1 << 15) str r0, [r5, #CLK_RESET_CLK_ENB_H_CLR] #endif #if defined (CONFIG_CACHE_L2X0) /* power up L2 */ ldr r0, [r2, #PMC_PWRGATE_STATUS] tst r0, #(1<= v7.1? mov32 r1, 0xC5ACCE55 mcrge p14, 0, r1, c1, c3, 4 @ DBGOSDLR #endif halted: isb dsb wfi /* CPU should be power gated here */ /* !!!FIXME!!! Implement halt failure handler */ b halted /* * tegra3_sdram_self_refresh * * called with MMU off and caches disabled /* puts sdram in self refresh * must execute from IRAM * r4 = TEGRA_PMC_BASE * r5 = TEGRA_CLK_RESET_BASE * r6 = TEGRA_FLOW_CTRL_BASE * r7 = TEGRA_TMRUS_BASE */ tegra3_sdram_self_refresh: adr r2, tegra3_sdram_pad_address adr r8, tegra3_sdram_pad_save mov r9, #0 padsave: ldr r0, [r2, r9] @ r0 is emc register address ldr r1, [r0] str r1, [r8, r9] @ save emc register add r9, r9, #4 ldr r0, tegra3_sdram_pad_size cmp r0, r9 bne padsave padsave_done: dsb mov32 r0, TEGRA_EMC_BASE @ r0 reserved for emc base mov r1, #0 str r1, [r0, #EMC_ZCAL_INTERVAL] str r1, [r0, #EMC_AUTO_CAL_INTERVAL] ldr r1, [r0, #EMC_CFG] bic r1, r1, #(1<<28) str r1, [r0, #EMC_CFG] @ disable DYN_SELF_REF emc_timing_update r1, r0 ldr r1, [r7] add r1, r1, #5 wait_until r1, r7, r2 emc_wait_audo_cal: ldr r1, [r0, #EMC_AUTO_CAL_STATUS] tst r1, #(0x1<<31) @ wait until AUTO_CAL_ACTIVE is clear bne emc_wait_audo_cal mov r1, #3 str r1, [r0, #EMC_REQ_CTRL] @ stall incoming DRAM requests emcidle: ldr r1, [r0, #EMC_EMC_STATUS] tst r1, #4 beq emcidle mov r1, #1 str r1, [r0, #EMC_SELF_REF] emc_device_mask r1, r0 emcself: ldr r2, [r0, #EMC_EMC_STATUS] and r2, r2, r1 cmp r2, r1 bne emcself @ loop until DDR in self-refresh ldr r1, [r0, #EMC_XM2VTTGENPADCTRL] mov32 r2, 0xF8F8FFFF @ clear XM2VTTGEN_DRVUP and XM2VTTGEN_DRVDN and r1, r1, r2 str r1, [r0, #EMC_XM2VTTGENPADCTRL] ldr r1, [r0, #EMC_XM2VTTGENPADCTRL2] orr r1, r1, #7 @ set E_NO_VTTGEN str r1, [r0, #EMC_XM2VTTGENPADCTRL2] emc_timing_update r1, r0 ldr r1, [r4, #PMC_CTRL] tst r1, #PMC_CTRL_SIDE_EFFECT_LP0 bne pmc_io_dpd_skip mov32 r1, 0x8EC00000 str r1, [r4, #PMC_IO_DPD_REQ] pmc_io_dpd_skip: dsb mov pc, lr .ltorg /* dummy symbol for end of IRAM */ .align L1_CACHE_SHIFT .globl tegra3_iram_end tegra3_iram_end: b . #endif