1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0-only */ 2*4882a593Smuzhiyun/* 3*4882a593Smuzhiyun * Copyright (c) 2012, NVIDIA Corporation. All rights reserved. 4*4882a593Smuzhiyun */ 5*4882a593Smuzhiyun 6*4882a593Smuzhiyun#include <linux/linkage.h> 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun#include <soc/tegra/flowctrl.h> 9*4882a593Smuzhiyun#include <soc/tegra/fuse.h> 10*4882a593Smuzhiyun 11*4882a593Smuzhiyun#include <asm/asm-offsets.h> 12*4882a593Smuzhiyun#include <asm/assembler.h> 13*4882a593Smuzhiyun#include <asm/cache.h> 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun#include "irammap.h" 16*4882a593Smuzhiyun#include "sleep.h" 17*4882a593Smuzhiyun 18*4882a593Smuzhiyun#define EMC_CFG 0xc 19*4882a593Smuzhiyun#define EMC_ADR_CFG 0x10 20*4882a593Smuzhiyun#define EMC_TIMING_CONTROL 0x28 21*4882a593Smuzhiyun#define EMC_NOP 0xdc 22*4882a593Smuzhiyun#define EMC_SELF_REF 0xe0 23*4882a593Smuzhiyun#define EMC_MRW 0xe8 24*4882a593Smuzhiyun#define EMC_FBIO_CFG5 0x104 25*4882a593Smuzhiyun#define EMC_AUTO_CAL_CONFIG 0x2a4 26*4882a593Smuzhiyun#define EMC_AUTO_CAL_INTERVAL 0x2a8 27*4882a593Smuzhiyun#define EMC_AUTO_CAL_STATUS 0x2ac 28*4882a593Smuzhiyun#define EMC_REQ_CTRL 0x2b0 29*4882a593Smuzhiyun#define EMC_CFG_DIG_DLL 0x2bc 30*4882a593Smuzhiyun#define EMC_EMC_STATUS 0x2b4 31*4882a593Smuzhiyun#define EMC_ZCAL_INTERVAL 0x2e0 32*4882a593Smuzhiyun#define EMC_ZQ_CAL 0x2ec 33*4882a593Smuzhiyun#define EMC_XM2VTTGENPADCTRL 0x310 34*4882a593Smuzhiyun#define EMC_XM2VTTGENPADCTRL2 0x314 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun#define PMC_CTRL 0x0 37*4882a593Smuzhiyun#define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */ 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun#define PMC_PLLP_WB0_OVERRIDE 0xf8 40*4882a593Smuzhiyun#define PMC_IO_DPD_REQ 0x1b8 41*4882a593Smuzhiyun#define PMC_IO_DPD_STATUS 0x1bc 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun#define CLK_RESET_CCLK_BURST 0x20 44*4882a593Smuzhiyun#define CLK_RESET_CCLK_DIVIDER 0x24 45*4882a593Smuzhiyun#define CLK_RESET_SCLK_BURST 0x28 46*4882a593Smuzhiyun#define CLK_RESET_SCLK_DIVIDER 0x2c 47*4882a593Smuzhiyun 48*4882a593Smuzhiyun#define CLK_RESET_PLLC_BASE 0x80 49*4882a593Smuzhiyun#define CLK_RESET_PLLC_MISC 0x8c 50*4882a593Smuzhiyun#define CLK_RESET_PLLM_BASE 0x90 51*4882a593Smuzhiyun#define CLK_RESET_PLLM_MISC 0x9c 52*4882a593Smuzhiyun#define CLK_RESET_PLLP_BASE 0xa0 53*4882a593Smuzhiyun#define CLK_RESET_PLLP_MISC 0xac 54*4882a593Smuzhiyun#define CLK_RESET_PLLA_BASE 0xb0 55*4882a593Smuzhiyun#define CLK_RESET_PLLA_MISC 0xbc 56*4882a593Smuzhiyun#define CLK_RESET_PLLX_BASE 0xe0 57*4882a593Smuzhiyun#define CLK_RESET_PLLX_MISC 0xe4 58*4882a593Smuzhiyun#define CLK_RESET_PLLX_MISC3 0x518 59*4882a593Smuzhiyun#define CLK_RESET_PLLX_MISC3_IDDQ 3 60*4882a593Smuzhiyun#define CLK_RESET_PLLM_MISC_IDDQ 5 61*4882a593Smuzhiyun#define CLK_RESET_PLLC_MISC_IDDQ 26 62*4882a593Smuzhiyun#define CLK_RESET_PLLP_RESHIFT 0x528 63*4882a593Smuzhiyun#define CLK_RESET_PLLP_RESHIFT_DEFAULT 0x3b 64*4882a593Smuzhiyun#define CLK_RESET_PLLP_RESHIFT_ENABLE 0x3 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun#define CLK_RESET_CLK_SOURCE_MSELECT 0x3b4 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun#define MSELECT_CLKM (0x3 << 30) 69*4882a593Smuzhiyun 70*4882a593Smuzhiyun#define LOCK_DELAY 50 /* safety delay after lock is detected */ 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun#define TEGRA30_POWER_HOTPLUG_SHUTDOWN (1 << 27) /* Hotplug shutdown */ 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun.macro emc_device_mask, rd, base 75*4882a593Smuzhiyun ldr \rd, [\base, #EMC_ADR_CFG] 76*4882a593Smuzhiyun tst \rd, #0x1 77*4882a593Smuzhiyun moveq \rd, #(0x1 << 8) @ just 1 device 78*4882a593Smuzhiyun movne \rd, #(0x3 << 8) @ 2 devices 79*4882a593Smuzhiyun.endm 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun.macro emc_timing_update, rd, base 82*4882a593Smuzhiyun mov \rd, #1 83*4882a593Smuzhiyun str \rd, [\base, #EMC_TIMING_CONTROL] 84*4882a593Smuzhiyun1001: 85*4882a593Smuzhiyun ldr \rd, [\base, #EMC_EMC_STATUS] 86*4882a593Smuzhiyun tst \rd, #(0x1<<23) @ wait EMC_STATUS_TIMING_UPDATE_STALLED is clear 87*4882a593Smuzhiyun bne 1001b 88*4882a593Smuzhiyun.endm 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun.macro pll_enable, rd, r_car_base, pll_base, pll_misc 91*4882a593Smuzhiyun ldr \rd, [\r_car_base, #\pll_base] 92*4882a593Smuzhiyun tst \rd, #(1 << 30) 93*4882a593Smuzhiyun orreq \rd, \rd, #(1 << 30) 94*4882a593Smuzhiyun streq \rd, [\r_car_base, #\pll_base] 95*4882a593Smuzhiyun /* Enable lock detector */ 96*4882a593Smuzhiyun .if \pll_misc 97*4882a593Smuzhiyun ldr \rd, [\r_car_base, #\pll_misc] 98*4882a593Smuzhiyun bic \rd, \rd, #(1 << 18) 99*4882a593Smuzhiyun str \rd, [\r_car_base, #\pll_misc] 100*4882a593Smuzhiyun ldr \rd, [\r_car_base, #\pll_misc] 101*4882a593Smuzhiyun ldr \rd, [\r_car_base, #\pll_misc] 102*4882a593Smuzhiyun orr \rd, \rd, #(1 << 18) 103*4882a593Smuzhiyun str \rd, [\r_car_base, #\pll_misc] 104*4882a593Smuzhiyun .endif 105*4882a593Smuzhiyun.endm 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun.macro pll_locked, rd, r_car_base, pll_base 108*4882a593Smuzhiyun1: 109*4882a593Smuzhiyun ldr \rd, [\r_car_base, #\pll_base] 110*4882a593Smuzhiyun tst \rd, #(1 << 27) 111*4882a593Smuzhiyun beq 1b 112*4882a593Smuzhiyun.endm 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun.macro pll_iddq_exit, rd, car, iddq, iddq_bit 115*4882a593Smuzhiyun ldr \rd, [\car, #\iddq] 116*4882a593Smuzhiyun bic \rd, \rd, #(1<<\iddq_bit) 117*4882a593Smuzhiyun str \rd, [\car, #\iddq] 118*4882a593Smuzhiyun.endm 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun.macro pll_iddq_entry, rd, car, iddq, iddq_bit 121*4882a593Smuzhiyun ldr \rd, [\car, #\iddq] 122*4882a593Smuzhiyun orr \rd, \rd, #(1<<\iddq_bit) 123*4882a593Smuzhiyun str \rd, [\car, #\iddq] 124*4882a593Smuzhiyun.endm 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PM_SLEEP) 127*4882a593Smuzhiyun/* 128*4882a593Smuzhiyun * tegra30_hotplug_shutdown(void) 129*4882a593Smuzhiyun * 130*4882a593Smuzhiyun * Powergates the current CPU. 131*4882a593Smuzhiyun * Should never return. 132*4882a593Smuzhiyun */ 133*4882a593SmuzhiyunENTRY(tegra30_hotplug_shutdown) 134*4882a593Smuzhiyun /* Powergate this CPU */ 135*4882a593Smuzhiyun mov r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN 136*4882a593Smuzhiyun bl tegra30_cpu_shutdown 137*4882a593Smuzhiyun ret lr @ should never get here 138*4882a593SmuzhiyunENDPROC(tegra30_hotplug_shutdown) 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun/* 141*4882a593Smuzhiyun * tegra30_cpu_shutdown(unsigned long flags) 142*4882a593Smuzhiyun * 143*4882a593Smuzhiyun * Puts the current CPU in wait-for-event mode on the flow controller 144*4882a593Smuzhiyun * and powergates it -- flags (in R0) indicate the request type. 145*4882a593Smuzhiyun * 146*4882a593Smuzhiyun * r10 = SoC ID 147*4882a593Smuzhiyun * corrupts r0-r4, r10-r12 148*4882a593Smuzhiyun */ 149*4882a593SmuzhiyunENTRY(tegra30_cpu_shutdown) 150*4882a593Smuzhiyun cpu_id r3 151*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_VIRT, r10 152*4882a593Smuzhiyun cmp r10, #TEGRA30 153*4882a593Smuzhiyun bne _no_cpu0_chk @ It's not Tegra30 154*4882a593Smuzhiyun 155*4882a593Smuzhiyun cmp r3, #0 156*4882a593Smuzhiyun reteq lr @ Must never be called for CPU 0 157*4882a593Smuzhiyun_no_cpu0_chk: 158*4882a593Smuzhiyun 159*4882a593Smuzhiyun ldr r12, =TEGRA_FLOW_CTRL_VIRT 160*4882a593Smuzhiyun cpu_to_csr_reg r1, r3 161*4882a593Smuzhiyun add r1, r1, r12 @ virtual CSR address for this CPU 162*4882a593Smuzhiyun cpu_to_halt_reg r2, r3 163*4882a593Smuzhiyun add r2, r2, r12 @ virtual HALT_EVENTS address for this CPU 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun /* 166*4882a593Smuzhiyun * Clear this CPU's "event" and "interrupt" flags and power gate 167*4882a593Smuzhiyun * it when halting but not before it is in the "WFE" state. 168*4882a593Smuzhiyun */ 169*4882a593Smuzhiyun movw r12, \ 170*4882a593Smuzhiyun FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG | \ 171*4882a593Smuzhiyun FLOW_CTRL_CSR_ENABLE 172*4882a593Smuzhiyun cmp r10, #TEGRA30 173*4882a593Smuzhiyun moveq r4, #(1 << 4) @ wfe bitmap 174*4882a593Smuzhiyun movne r4, #(1 << 8) @ wfi bitmap 175*4882a593Smuzhiyun ARM( orr r12, r12, r4, lsl r3 ) 176*4882a593Smuzhiyun THUMB( lsl r4, r4, r3 ) 177*4882a593Smuzhiyun THUMB( orr r12, r12, r4 ) 178*4882a593Smuzhiyun str r12, [r1] 179*4882a593Smuzhiyun 180*4882a593Smuzhiyun /* Halt this CPU. */ 181*4882a593Smuzhiyun mov r3, #0x400 182*4882a593Smuzhiyundelay_1: 183*4882a593Smuzhiyun subs r3, r3, #1 @ delay as a part of wfe war. 184*4882a593Smuzhiyun bge delay_1; 185*4882a593Smuzhiyun cpsid a @ disable imprecise aborts. 186*4882a593Smuzhiyun ldr r3, [r1] @ read CSR 187*4882a593Smuzhiyun str r3, [r1] @ clear CSR 188*4882a593Smuzhiyun 189*4882a593Smuzhiyun tst r0, #TEGRA30_POWER_HOTPLUG_SHUTDOWN 190*4882a593Smuzhiyun beq flow_ctrl_setting_for_lp2 191*4882a593Smuzhiyun 192*4882a593Smuzhiyun /* flow controller set up for hotplug */ 193*4882a593Smuzhiyun mov r3, #FLOW_CTRL_WAITEVENT @ For hotplug 194*4882a593Smuzhiyun b flow_ctrl_done 195*4882a593Smuzhiyunflow_ctrl_setting_for_lp2: 196*4882a593Smuzhiyun /* flow controller set up for LP2 */ 197*4882a593Smuzhiyun cmp r10, #TEGRA30 198*4882a593Smuzhiyun moveq r3, #FLOW_CTRL_WAIT_FOR_INTERRUPT @ For LP2 199*4882a593Smuzhiyun movne r3, #FLOW_CTRL_WAITEVENT 200*4882a593Smuzhiyun orrne r3, r3, #FLOW_CTRL_HALT_GIC_IRQ 201*4882a593Smuzhiyun orrne r3, r3, #FLOW_CTRL_HALT_GIC_FIQ 202*4882a593Smuzhiyunflow_ctrl_done: 203*4882a593Smuzhiyun cmp r10, #TEGRA30 204*4882a593Smuzhiyun str r3, [r2] 205*4882a593Smuzhiyun ldr r0, [r2] 206*4882a593Smuzhiyun b wfe_war 207*4882a593Smuzhiyun 208*4882a593Smuzhiyun__cpu_reset_again: 209*4882a593Smuzhiyun dsb 210*4882a593Smuzhiyun .align 5 211*4882a593Smuzhiyun wfeeq @ CPU should be power gated here 212*4882a593Smuzhiyun wfine 213*4882a593Smuzhiyunwfe_war: 214*4882a593Smuzhiyun b __cpu_reset_again 215*4882a593Smuzhiyun 216*4882a593Smuzhiyun /* 217*4882a593Smuzhiyun * 38 nop's, which fills rest of wfe cache line and 218*4882a593Smuzhiyun * 4 more cachelines with nop 219*4882a593Smuzhiyun */ 220*4882a593Smuzhiyun .rept 38 221*4882a593Smuzhiyun nop 222*4882a593Smuzhiyun .endr 223*4882a593Smuzhiyun b . @ should never get here 224*4882a593Smuzhiyun 225*4882a593SmuzhiyunENDPROC(tegra30_cpu_shutdown) 226*4882a593Smuzhiyun#endif 227*4882a593Smuzhiyun 228*4882a593Smuzhiyun#ifdef CONFIG_PM_SLEEP 229*4882a593Smuzhiyun/* 230*4882a593Smuzhiyun * tegra30_sleep_core_finish(unsigned long v2p) 231*4882a593Smuzhiyun * 232*4882a593Smuzhiyun * Enters suspend in LP0 or LP1 by turning off the MMU and jumping to 233*4882a593Smuzhiyun * tegra30_tear_down_core in IRAM 234*4882a593Smuzhiyun */ 235*4882a593SmuzhiyunENTRY(tegra30_sleep_core_finish) 236*4882a593Smuzhiyun mov r4, r0 237*4882a593Smuzhiyun /* Flush, disable the L1 data cache and exit SMP */ 238*4882a593Smuzhiyun mov r0, #TEGRA_FLUSH_CACHE_ALL 239*4882a593Smuzhiyun bl tegra_disable_clean_inv_dcache 240*4882a593Smuzhiyun mov r0, r4 241*4882a593Smuzhiyun 242*4882a593Smuzhiyun /* 243*4882a593Smuzhiyun * Preload all the address literals that are needed for the 244*4882a593Smuzhiyun * CPU power-gating process, to avoid loading from SDRAM which 245*4882a593Smuzhiyun * are not supported once SDRAM is put into self-refresh. 246*4882a593Smuzhiyun * LP0 / LP1 use physical address, since the MMU needs to be 247*4882a593Smuzhiyun * disabled before putting SDRAM into self-refresh to avoid 248*4882a593Smuzhiyun * memory access due to page table walks. 249*4882a593Smuzhiyun */ 250*4882a593Smuzhiyun mov32 r4, TEGRA_PMC_BASE 251*4882a593Smuzhiyun mov32 r5, TEGRA_CLK_RESET_BASE 252*4882a593Smuzhiyun mov32 r6, TEGRA_FLOW_CTRL_BASE 253*4882a593Smuzhiyun mov32 r7, TEGRA_TMRUS_BASE 254*4882a593Smuzhiyun 255*4882a593Smuzhiyun mov32 r3, tegra_shut_off_mmu 256*4882a593Smuzhiyun add r3, r3, r0 257*4882a593Smuzhiyun 258*4882a593Smuzhiyun mov32 r0, tegra30_tear_down_core 259*4882a593Smuzhiyun mov32 r1, tegra30_iram_start 260*4882a593Smuzhiyun sub r0, r0, r1 261*4882a593Smuzhiyun mov32 r1, TEGRA_IRAM_LPx_RESUME_AREA 262*4882a593Smuzhiyun add r0, r0, r1 263*4882a593Smuzhiyun 264*4882a593Smuzhiyun ret r3 265*4882a593SmuzhiyunENDPROC(tegra30_sleep_core_finish) 266*4882a593Smuzhiyun 267*4882a593Smuzhiyun/* 268*4882a593Smuzhiyun * tegra30_pm_secondary_cpu_suspend(unsigned long unused_arg) 269*4882a593Smuzhiyun * 270*4882a593Smuzhiyun * Enters LP2 on secondary CPU by exiting coherency and powergating the CPU. 271*4882a593Smuzhiyun */ 272*4882a593SmuzhiyunENTRY(tegra30_pm_secondary_cpu_suspend) 273*4882a593Smuzhiyun mov r7, lr 274*4882a593Smuzhiyun 275*4882a593Smuzhiyun /* Flush and disable the L1 data cache */ 276*4882a593Smuzhiyun mov r0, #TEGRA_FLUSH_CACHE_LOUIS 277*4882a593Smuzhiyun bl tegra_disable_clean_inv_dcache 278*4882a593Smuzhiyun 279*4882a593Smuzhiyun /* Powergate this CPU. */ 280*4882a593Smuzhiyun mov r0, #0 @ power mode flags (!hotplug) 281*4882a593Smuzhiyun bl tegra30_cpu_shutdown 282*4882a593Smuzhiyun mov r0, #1 @ never return here 283*4882a593Smuzhiyun ret r7 284*4882a593SmuzhiyunENDPROC(tegra30_pm_secondary_cpu_suspend) 285*4882a593Smuzhiyun 286*4882a593Smuzhiyun/* 287*4882a593Smuzhiyun * tegra30_tear_down_cpu 288*4882a593Smuzhiyun * 289*4882a593Smuzhiyun * Switches the CPU to enter sleep. 290*4882a593Smuzhiyun */ 291*4882a593SmuzhiyunENTRY(tegra30_tear_down_cpu) 292*4882a593Smuzhiyun mov32 r6, TEGRA_FLOW_CTRL_BASE 293*4882a593Smuzhiyun 294*4882a593Smuzhiyun b tegra30_enter_sleep 295*4882a593SmuzhiyunENDPROC(tegra30_tear_down_cpu) 296*4882a593Smuzhiyun 297*4882a593Smuzhiyun/* START OF ROUTINES COPIED TO IRAM */ 298*4882a593Smuzhiyun .align L1_CACHE_SHIFT 299*4882a593Smuzhiyun .globl tegra30_iram_start 300*4882a593Smuzhiyuntegra30_iram_start: 301*4882a593Smuzhiyun 302*4882a593Smuzhiyun/* 303*4882a593Smuzhiyun * tegra30_lp1_reset 304*4882a593Smuzhiyun * 305*4882a593Smuzhiyun * reset vector for LP1 restore; copied into IRAM during suspend. 306*4882a593Smuzhiyun * Brings the system back up to a safe staring point (SDRAM out of 307*4882a593Smuzhiyun * self-refresh, PLLC, PLLM and PLLP reenabled, CPU running on PLLX, 308*4882a593Smuzhiyun * system clock running on the same PLL that it suspended at), and 309*4882a593Smuzhiyun * jumps to tegra_resume to restore virtual addressing. 310*4882a593Smuzhiyun * The physical address of tegra_resume expected to be stored in 311*4882a593Smuzhiyun * PMC_SCRATCH41. 312*4882a593Smuzhiyun * 313*4882a593Smuzhiyun * NOTE: THIS *MUST* BE RELOCATED TO TEGRA_IRAM_LPx_RESUME_AREA. 314*4882a593Smuzhiyun */ 315*4882a593SmuzhiyunENTRY(tegra30_lp1_reset) 316*4882a593Smuzhiyun /* 317*4882a593Smuzhiyun * The CPU and system bus are running at 32KHz and executing from 318*4882a593Smuzhiyun * IRAM when this code is executed; immediately switch to CLKM and 319*4882a593Smuzhiyun * enable PLLP, PLLM, PLLC, PLLA and PLLX. 320*4882a593Smuzhiyun */ 321*4882a593Smuzhiyun mov32 r0, TEGRA_CLK_RESET_BASE 322*4882a593Smuzhiyun 323*4882a593Smuzhiyun mov r1, #(1 << 28) 324*4882a593Smuzhiyun str r1, [r0, #CLK_RESET_SCLK_BURST] 325*4882a593Smuzhiyun str r1, [r0, #CLK_RESET_CCLK_BURST] 326*4882a593Smuzhiyun mov r1, #0 327*4882a593Smuzhiyun str r1, [r0, #CLK_RESET_CCLK_DIVIDER] 328*4882a593Smuzhiyun str r1, [r0, #CLK_RESET_SCLK_DIVIDER] 329*4882a593Smuzhiyun 330*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_BASE, r10 331*4882a593Smuzhiyun cmp r10, #TEGRA30 332*4882a593Smuzhiyun beq _no_pll_iddq_exit 333*4882a593Smuzhiyun 334*4882a593Smuzhiyun pll_iddq_exit r1, r0, CLK_RESET_PLLM_MISC, CLK_RESET_PLLM_MISC_IDDQ 335*4882a593Smuzhiyun pll_iddq_exit r1, r0, CLK_RESET_PLLC_MISC, CLK_RESET_PLLC_MISC_IDDQ 336*4882a593Smuzhiyun pll_iddq_exit r1, r0, CLK_RESET_PLLX_MISC3, CLK_RESET_PLLX_MISC3_IDDQ 337*4882a593Smuzhiyun 338*4882a593Smuzhiyun mov32 r7, TEGRA_TMRUS_BASE 339*4882a593Smuzhiyun ldr r1, [r7] 340*4882a593Smuzhiyun add r1, r1, #2 341*4882a593Smuzhiyun wait_until r1, r7, r3 342*4882a593Smuzhiyun 343*4882a593Smuzhiyun /* enable PLLM via PMC */ 344*4882a593Smuzhiyun mov32 r2, TEGRA_PMC_BASE 345*4882a593Smuzhiyun ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE] 346*4882a593Smuzhiyun orr r1, r1, #(1 << 12) 347*4882a593Smuzhiyun str r1, [r2, #PMC_PLLP_WB0_OVERRIDE] 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun pll_enable r1, r0, CLK_RESET_PLLM_BASE, 0 350*4882a593Smuzhiyun pll_enable r1, r0, CLK_RESET_PLLC_BASE, 0 351*4882a593Smuzhiyun pll_enable r1, r0, CLK_RESET_PLLX_BASE, 0 352*4882a593Smuzhiyun 353*4882a593Smuzhiyun b _pll_m_c_x_done 354*4882a593Smuzhiyun 355*4882a593Smuzhiyun_no_pll_iddq_exit: 356*4882a593Smuzhiyun /* enable PLLM via PMC */ 357*4882a593Smuzhiyun mov32 r2, TEGRA_PMC_BASE 358*4882a593Smuzhiyun ldr r1, [r2, #PMC_PLLP_WB0_OVERRIDE] 359*4882a593Smuzhiyun orr r1, r1, #(1 << 12) 360*4882a593Smuzhiyun str r1, [r2, #PMC_PLLP_WB0_OVERRIDE] 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun pll_enable r1, r0, CLK_RESET_PLLM_BASE, CLK_RESET_PLLM_MISC 363*4882a593Smuzhiyun pll_enable r1, r0, CLK_RESET_PLLC_BASE, CLK_RESET_PLLC_MISC 364*4882a593Smuzhiyun 365*4882a593Smuzhiyun_pll_m_c_x_done: 366*4882a593Smuzhiyun pll_enable r1, r0, CLK_RESET_PLLP_BASE, CLK_RESET_PLLP_MISC 367*4882a593Smuzhiyun pll_enable r1, r0, CLK_RESET_PLLA_BASE, CLK_RESET_PLLA_MISC 368*4882a593Smuzhiyun 369*4882a593Smuzhiyun pll_locked r1, r0, CLK_RESET_PLLM_BASE 370*4882a593Smuzhiyun pll_locked r1, r0, CLK_RESET_PLLP_BASE 371*4882a593Smuzhiyun pll_locked r1, r0, CLK_RESET_PLLA_BASE 372*4882a593Smuzhiyun pll_locked r1, r0, CLK_RESET_PLLC_BASE 373*4882a593Smuzhiyun 374*4882a593Smuzhiyun /* 375*4882a593Smuzhiyun * CPUFreq driver could select other PLL for CPU. PLLX will be 376*4882a593Smuzhiyun * enabled by the Tegra30 CLK driver on an as-needed basis, see 377*4882a593Smuzhiyun * tegra30_cpu_clock_resume(). 378*4882a593Smuzhiyun */ 379*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_BASE, r1 380*4882a593Smuzhiyun cmp r1, #TEGRA30 381*4882a593Smuzhiyun beq 1f 382*4882a593Smuzhiyun 383*4882a593Smuzhiyun pll_locked r1, r0, CLK_RESET_PLLX_BASE 384*4882a593Smuzhiyun 385*4882a593Smuzhiyun ldr r1, [r0, #CLK_RESET_PLLP_BASE] 386*4882a593Smuzhiyun bic r1, r1, #(1<<31) @ disable PllP bypass 387*4882a593Smuzhiyun str r1, [r0, #CLK_RESET_PLLP_BASE] 388*4882a593Smuzhiyun 389*4882a593Smuzhiyun mov r1, #CLK_RESET_PLLP_RESHIFT_DEFAULT 390*4882a593Smuzhiyun str r1, [r0, #CLK_RESET_PLLP_RESHIFT] 391*4882a593Smuzhiyun1: 392*4882a593Smuzhiyun 393*4882a593Smuzhiyun mov32 r7, TEGRA_TMRUS_BASE 394*4882a593Smuzhiyun ldr r1, [r7] 395*4882a593Smuzhiyun add r1, r1, #LOCK_DELAY 396*4882a593Smuzhiyun wait_until r1, r7, r3 397*4882a593Smuzhiyun 398*4882a593Smuzhiyun adr r5, tegra_sdram_pad_save 399*4882a593Smuzhiyun 400*4882a593Smuzhiyun ldr r4, [r5, #0x18] @ restore CLK_SOURCE_MSELECT 401*4882a593Smuzhiyun str r4, [r0, #CLK_RESET_CLK_SOURCE_MSELECT] 402*4882a593Smuzhiyun 403*4882a593Smuzhiyun ldr r4, [r5, #0x1C] @ restore SCLK_BURST 404*4882a593Smuzhiyun str r4, [r0, #CLK_RESET_SCLK_BURST] 405*4882a593Smuzhiyun 406*4882a593Smuzhiyun movw r4, #:lower16:((1 << 28) | (0x4)) @ burst policy is PLLP 407*4882a593Smuzhiyun movt r4, #:upper16:((1 << 28) | (0x4)) 408*4882a593Smuzhiyun str r4, [r0, #CLK_RESET_CCLK_BURST] 409*4882a593Smuzhiyun 410*4882a593Smuzhiyun /* Restore pad power state to normal */ 411*4882a593Smuzhiyun ldr r1, [r5, #0x14] @ PMC_IO_DPD_STATUS 412*4882a593Smuzhiyun mvn r1, r1 413*4882a593Smuzhiyun bic r1, r1, #(1 << 31) 414*4882a593Smuzhiyun orr r1, r1, #(1 << 30) 415*4882a593Smuzhiyun str r1, [r2, #PMC_IO_DPD_REQ] @ DPD_OFF 416*4882a593Smuzhiyun 417*4882a593Smuzhiyun cmp r10, #TEGRA30 418*4882a593Smuzhiyun movweq r0, #:lower16:TEGRA_EMC_BASE @ r0 reserved for emc base 419*4882a593Smuzhiyun movteq r0, #:upper16:TEGRA_EMC_BASE 420*4882a593Smuzhiyun cmp r10, #TEGRA114 421*4882a593Smuzhiyun movweq r0, #:lower16:TEGRA_EMC0_BASE 422*4882a593Smuzhiyun movteq r0, #:upper16:TEGRA_EMC0_BASE 423*4882a593Smuzhiyun cmp r10, #TEGRA124 424*4882a593Smuzhiyun movweq r0, #:lower16:TEGRA124_EMC_BASE 425*4882a593Smuzhiyun movteq r0, #:upper16:TEGRA124_EMC_BASE 426*4882a593Smuzhiyun 427*4882a593Smuzhiyunexit_self_refresh: 428*4882a593Smuzhiyun ldr r1, [r5, #0xC] @ restore EMC_XM2VTTGENPADCTRL 429*4882a593Smuzhiyun str r1, [r0, #EMC_XM2VTTGENPADCTRL] 430*4882a593Smuzhiyun ldr r1, [r5, #0x10] @ restore EMC_XM2VTTGENPADCTRL2 431*4882a593Smuzhiyun str r1, [r0, #EMC_XM2VTTGENPADCTRL2] 432*4882a593Smuzhiyun ldr r1, [r5, #0x8] @ restore EMC_AUTO_CAL_INTERVAL 433*4882a593Smuzhiyun str r1, [r0, #EMC_AUTO_CAL_INTERVAL] 434*4882a593Smuzhiyun 435*4882a593Smuzhiyun /* Relock DLL */ 436*4882a593Smuzhiyun ldr r1, [r0, #EMC_CFG_DIG_DLL] 437*4882a593Smuzhiyun orr r1, r1, #(1 << 30) @ set DLL_RESET 438*4882a593Smuzhiyun str r1, [r0, #EMC_CFG_DIG_DLL] 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun emc_timing_update r1, r0 441*4882a593Smuzhiyun 442*4882a593Smuzhiyun cmp r10, #TEGRA114 443*4882a593Smuzhiyun movweq r1, #:lower16:TEGRA_EMC1_BASE 444*4882a593Smuzhiyun movteq r1, #:upper16:TEGRA_EMC1_BASE 445*4882a593Smuzhiyun cmpeq r0, r1 446*4882a593Smuzhiyun 447*4882a593Smuzhiyun ldr r1, [r0, #EMC_AUTO_CAL_CONFIG] 448*4882a593Smuzhiyun orr r1, r1, #(1 << 31) @ set AUTO_CAL_ACTIVE 449*4882a593Smuzhiyun orreq r1, r1, #(1 << 27) @ set slave mode for channel 1 450*4882a593Smuzhiyun str r1, [r0, #EMC_AUTO_CAL_CONFIG] 451*4882a593Smuzhiyun 452*4882a593Smuzhiyunemc_wait_auto_cal_onetime: 453*4882a593Smuzhiyun ldr r1, [r0, #EMC_AUTO_CAL_STATUS] 454*4882a593Smuzhiyun tst r1, #(1 << 31) @ wait until AUTO_CAL_ACTIVE is cleared 455*4882a593Smuzhiyun bne emc_wait_auto_cal_onetime 456*4882a593Smuzhiyun 457*4882a593Smuzhiyun ldr r1, [r0, #EMC_CFG] 458*4882a593Smuzhiyun bic r1, r1, #(1 << 31) @ disable DRAM_CLK_STOP_PD 459*4882a593Smuzhiyun str r1, [r0, #EMC_CFG] 460*4882a593Smuzhiyun 461*4882a593Smuzhiyun mov r1, #0 462*4882a593Smuzhiyun str r1, [r0, #EMC_SELF_REF] @ take DRAM out of self refresh 463*4882a593Smuzhiyun mov r1, #1 464*4882a593Smuzhiyun cmp r10, #TEGRA30 465*4882a593Smuzhiyun streq r1, [r0, #EMC_NOP] 466*4882a593Smuzhiyun streq r1, [r0, #EMC_NOP] 467*4882a593Smuzhiyun 468*4882a593Smuzhiyun emc_device_mask r1, r0 469*4882a593Smuzhiyun 470*4882a593Smuzhiyunexit_selfrefresh_loop: 471*4882a593Smuzhiyun ldr r2, [r0, #EMC_EMC_STATUS] 472*4882a593Smuzhiyun ands r2, r2, r1 473*4882a593Smuzhiyun bne exit_selfrefresh_loop 474*4882a593Smuzhiyun 475*4882a593Smuzhiyun lsr r1, r1, #8 @ devSel, bit0:dev0, bit1:dev1 476*4882a593Smuzhiyun 477*4882a593Smuzhiyun mov32 r7, TEGRA_TMRUS_BASE 478*4882a593Smuzhiyun ldr r2, [r0, #EMC_FBIO_CFG5] 479*4882a593Smuzhiyun 480*4882a593Smuzhiyun and r2, r2, #3 @ check DRAM_TYPE 481*4882a593Smuzhiyun cmp r2, #2 482*4882a593Smuzhiyun beq emc_lpddr2 483*4882a593Smuzhiyun 484*4882a593Smuzhiyun /* Issue a ZQ_CAL for dev0 - DDR3 */ 485*4882a593Smuzhiyun mov32 r2, 0x80000011 @ DEV_SELECTION=2, LENGTH=LONG, CMD=1 486*4882a593Smuzhiyun str r2, [r0, #EMC_ZQ_CAL] 487*4882a593Smuzhiyun ldr r2, [r7] 488*4882a593Smuzhiyun add r2, r2, #10 489*4882a593Smuzhiyun wait_until r2, r7, r3 490*4882a593Smuzhiyun 491*4882a593Smuzhiyun tst r1, #2 492*4882a593Smuzhiyun beq zcal_done 493*4882a593Smuzhiyun 494*4882a593Smuzhiyun /* Issue a ZQ_CAL for dev1 - DDR3 */ 495*4882a593Smuzhiyun mov32 r2, 0x40000011 @ DEV_SELECTION=1, LENGTH=LONG, CMD=1 496*4882a593Smuzhiyun str r2, [r0, #EMC_ZQ_CAL] 497*4882a593Smuzhiyun ldr r2, [r7] 498*4882a593Smuzhiyun add r2, r2, #10 499*4882a593Smuzhiyun wait_until r2, r7, r3 500*4882a593Smuzhiyun b zcal_done 501*4882a593Smuzhiyun 502*4882a593Smuzhiyunemc_lpddr2: 503*4882a593Smuzhiyun /* Issue a ZQ_CAL for dev0 - LPDDR2 */ 504*4882a593Smuzhiyun mov32 r2, 0x800A00AB @ DEV_SELECTION=2, MA=10, OP=0xAB 505*4882a593Smuzhiyun str r2, [r0, #EMC_MRW] 506*4882a593Smuzhiyun ldr r2, [r7] 507*4882a593Smuzhiyun add r2, r2, #1 508*4882a593Smuzhiyun wait_until r2, r7, r3 509*4882a593Smuzhiyun 510*4882a593Smuzhiyun tst r1, #2 511*4882a593Smuzhiyun beq zcal_done 512*4882a593Smuzhiyun 513*4882a593Smuzhiyun /* Issue a ZQ_CAL for dev0 - LPDDR2 */ 514*4882a593Smuzhiyun mov32 r2, 0x400A00AB @ DEV_SELECTION=1, MA=10, OP=0xAB 515*4882a593Smuzhiyun str r2, [r0, #EMC_MRW] 516*4882a593Smuzhiyun ldr r2, [r7] 517*4882a593Smuzhiyun add r2, r2, #1 518*4882a593Smuzhiyun wait_until r2, r7, r3 519*4882a593Smuzhiyun 520*4882a593Smuzhiyunzcal_done: 521*4882a593Smuzhiyun mov r1, #0 @ unstall all transactions 522*4882a593Smuzhiyun str r1, [r0, #EMC_REQ_CTRL] 523*4882a593Smuzhiyun ldr r1, [r5, #0x4] @ restore EMC_ZCAL_INTERVAL 524*4882a593Smuzhiyun str r1, [r0, #EMC_ZCAL_INTERVAL] 525*4882a593Smuzhiyun ldr r1, [r5, #0x0] @ restore EMC_CFG 526*4882a593Smuzhiyun str r1, [r0, #EMC_CFG] 527*4882a593Smuzhiyun 528*4882a593Smuzhiyun emc_timing_update r1, r0 529*4882a593Smuzhiyun 530*4882a593Smuzhiyun /* Tegra114 had dual EMC channel, now config the other one */ 531*4882a593Smuzhiyun cmp r10, #TEGRA114 532*4882a593Smuzhiyun bne __no_dual_emc_chanl 533*4882a593Smuzhiyun mov32 r1, TEGRA_EMC1_BASE 534*4882a593Smuzhiyun cmp r0, r1 535*4882a593Smuzhiyun movne r0, r1 536*4882a593Smuzhiyun addne r5, r5, #0x20 537*4882a593Smuzhiyun bne exit_self_refresh 538*4882a593Smuzhiyun__no_dual_emc_chanl: 539*4882a593Smuzhiyun 540*4882a593Smuzhiyun mov32 r0, TEGRA_PMC_BASE 541*4882a593Smuzhiyun ldr r0, [r0, #PMC_SCRATCH41] 542*4882a593Smuzhiyun ret r0 @ jump to tegra_resume 543*4882a593SmuzhiyunENDPROC(tegra30_lp1_reset) 544*4882a593Smuzhiyun 545*4882a593Smuzhiyun .align L1_CACHE_SHIFT 546*4882a593Smuzhiyuntegra30_sdram_pad_address: 547*4882a593Smuzhiyun .word TEGRA_EMC_BASE + EMC_CFG @0x0 548*4882a593Smuzhiyun .word TEGRA_EMC_BASE + EMC_ZCAL_INTERVAL @0x4 549*4882a593Smuzhiyun .word TEGRA_EMC_BASE + EMC_AUTO_CAL_INTERVAL @0x8 550*4882a593Smuzhiyun .word TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL @0xc 551*4882a593Smuzhiyun .word TEGRA_EMC_BASE + EMC_XM2VTTGENPADCTRL2 @0x10 552*4882a593Smuzhiyun .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 553*4882a593Smuzhiyun .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 554*4882a593Smuzhiyun .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c 555*4882a593Smuzhiyuntegra30_sdram_pad_address_end: 556*4882a593Smuzhiyun 557*4882a593Smuzhiyuntegra114_sdram_pad_address: 558*4882a593Smuzhiyun .word TEGRA_EMC0_BASE + EMC_CFG @0x0 559*4882a593Smuzhiyun .word TEGRA_EMC0_BASE + EMC_ZCAL_INTERVAL @0x4 560*4882a593Smuzhiyun .word TEGRA_EMC0_BASE + EMC_AUTO_CAL_INTERVAL @0x8 561*4882a593Smuzhiyun .word TEGRA_EMC0_BASE + EMC_XM2VTTGENPADCTRL @0xc 562*4882a593Smuzhiyun .word TEGRA_EMC0_BASE + EMC_XM2VTTGENPADCTRL2 @0x10 563*4882a593Smuzhiyun .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 564*4882a593Smuzhiyun .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 565*4882a593Smuzhiyun .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c 566*4882a593Smuzhiyun .word TEGRA_EMC1_BASE + EMC_CFG @0x20 567*4882a593Smuzhiyun .word TEGRA_EMC1_BASE + EMC_ZCAL_INTERVAL @0x24 568*4882a593Smuzhiyun .word TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL @0x28 569*4882a593Smuzhiyun .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL @0x2c 570*4882a593Smuzhiyun .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2 @0x30 571*4882a593Smuzhiyuntegra114_sdram_pad_adress_end: 572*4882a593Smuzhiyun 573*4882a593Smuzhiyuntegra124_sdram_pad_address: 574*4882a593Smuzhiyun .word TEGRA124_EMC_BASE + EMC_CFG @0x0 575*4882a593Smuzhiyun .word TEGRA124_EMC_BASE + EMC_ZCAL_INTERVAL @0x4 576*4882a593Smuzhiyun .word TEGRA124_EMC_BASE + EMC_AUTO_CAL_INTERVAL @0x8 577*4882a593Smuzhiyun .word TEGRA124_EMC_BASE + EMC_XM2VTTGENPADCTRL @0xc 578*4882a593Smuzhiyun .word TEGRA124_EMC_BASE + EMC_XM2VTTGENPADCTRL2 @0x10 579*4882a593Smuzhiyun .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 580*4882a593Smuzhiyun .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 581*4882a593Smuzhiyun .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c 582*4882a593Smuzhiyuntegra124_sdram_pad_address_end: 583*4882a593Smuzhiyun 584*4882a593Smuzhiyuntegra30_sdram_pad_size: 585*4882a593Smuzhiyun .word tegra30_sdram_pad_address_end - tegra30_sdram_pad_address 586*4882a593Smuzhiyun 587*4882a593Smuzhiyuntegra114_sdram_pad_size: 588*4882a593Smuzhiyun .word tegra114_sdram_pad_adress_end - tegra114_sdram_pad_address 589*4882a593Smuzhiyun 590*4882a593Smuzhiyun .type tegra_sdram_pad_save, %object 591*4882a593Smuzhiyuntegra_sdram_pad_save: 592*4882a593Smuzhiyun .rept (tegra114_sdram_pad_adress_end - tegra114_sdram_pad_address) / 4 593*4882a593Smuzhiyun .long 0 594*4882a593Smuzhiyun .endr 595*4882a593Smuzhiyun 596*4882a593Smuzhiyun/* 597*4882a593Smuzhiyun * tegra30_tear_down_core 598*4882a593Smuzhiyun * 599*4882a593Smuzhiyun * copied into and executed from IRAM 600*4882a593Smuzhiyun * puts memory in self-refresh for LP0 and LP1 601*4882a593Smuzhiyun */ 602*4882a593Smuzhiyuntegra30_tear_down_core: 603*4882a593Smuzhiyun bl tegra30_sdram_self_refresh 604*4882a593Smuzhiyun bl tegra30_switch_cpu_to_clk32k 605*4882a593Smuzhiyun b tegra30_enter_sleep 606*4882a593Smuzhiyun 607*4882a593Smuzhiyun/* 608*4882a593Smuzhiyun * tegra30_switch_cpu_to_clk32k 609*4882a593Smuzhiyun * 610*4882a593Smuzhiyun * In LP0 and LP1 all PLLs will be turned off. Switching the CPU and System CLK 611*4882a593Smuzhiyun * to the 32KHz clock. 612*4882a593Smuzhiyun * r4 = TEGRA_PMC_BASE 613*4882a593Smuzhiyun * r5 = TEGRA_CLK_RESET_BASE 614*4882a593Smuzhiyun * r6 = TEGRA_FLOW_CTRL_BASE 615*4882a593Smuzhiyun * r7 = TEGRA_TMRUS_BASE 616*4882a593Smuzhiyun * r10= SoC ID 617*4882a593Smuzhiyun */ 618*4882a593Smuzhiyuntegra30_switch_cpu_to_clk32k: 619*4882a593Smuzhiyun /* 620*4882a593Smuzhiyun * start by jumping to CLKM to safely disable PLLs, then jump to 621*4882a593Smuzhiyun * CLKS. 622*4882a593Smuzhiyun */ 623*4882a593Smuzhiyun mov r0, #(1 << 28) 624*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_SCLK_BURST] 625*4882a593Smuzhiyun /* 2uS delay delay between changing SCLK and CCLK */ 626*4882a593Smuzhiyun ldr r1, [r7] 627*4882a593Smuzhiyun add r1, r1, #2 628*4882a593Smuzhiyun wait_until r1, r7, r9 629*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_CCLK_BURST] 630*4882a593Smuzhiyun mov r0, #0 631*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_CCLK_DIVIDER] 632*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_SCLK_DIVIDER] 633*4882a593Smuzhiyun 634*4882a593Smuzhiyun /* switch the clock source of mselect to be CLK_M */ 635*4882a593Smuzhiyun ldr r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT] 636*4882a593Smuzhiyun orr r0, r0, #MSELECT_CLKM 637*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_CLK_SOURCE_MSELECT] 638*4882a593Smuzhiyun 639*4882a593Smuzhiyun /* 2uS delay delay between changing SCLK and disabling PLLs */ 640*4882a593Smuzhiyun ldr r1, [r7] 641*4882a593Smuzhiyun add r1, r1, #2 642*4882a593Smuzhiyun wait_until r1, r7, r9 643*4882a593Smuzhiyun 644*4882a593Smuzhiyun /* disable PLLM via PMC in LP1 */ 645*4882a593Smuzhiyun ldr r0, [r4, #PMC_PLLP_WB0_OVERRIDE] 646*4882a593Smuzhiyun bic r0, r0, #(1 << 12) 647*4882a593Smuzhiyun str r0, [r4, #PMC_PLLP_WB0_OVERRIDE] 648*4882a593Smuzhiyun 649*4882a593Smuzhiyun /* disable PLLP, PLLA, PLLC and PLLX */ 650*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_BASE, r1 651*4882a593Smuzhiyun cmp r1, #TEGRA30 652*4882a593Smuzhiyun ldr r0, [r5, #CLK_RESET_PLLP_BASE] 653*4882a593Smuzhiyun orrne r0, r0, #(1 << 31) @ enable PllP bypass on fast cluster 654*4882a593Smuzhiyun bic r0, r0, #(1 << 30) 655*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_PLLP_BASE] 656*4882a593Smuzhiyun beq 1f 657*4882a593Smuzhiyun mov r0, #CLK_RESET_PLLP_RESHIFT_ENABLE 658*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_PLLP_RESHIFT] 659*4882a593Smuzhiyun1: 660*4882a593Smuzhiyun ldr r0, [r5, #CLK_RESET_PLLA_BASE] 661*4882a593Smuzhiyun bic r0, r0, #(1 << 30) 662*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_PLLA_BASE] 663*4882a593Smuzhiyun ldr r0, [r5, #CLK_RESET_PLLC_BASE] 664*4882a593Smuzhiyun bic r0, r0, #(1 << 30) 665*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_PLLC_BASE] 666*4882a593Smuzhiyun ldr r0, [r5, #CLK_RESET_PLLX_BASE] 667*4882a593Smuzhiyun bic r0, r0, #(1 << 30) 668*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_PLLX_BASE] 669*4882a593Smuzhiyun 670*4882a593Smuzhiyun cmp r10, #TEGRA30 671*4882a593Smuzhiyun beq _no_pll_in_iddq 672*4882a593Smuzhiyun pll_iddq_entry r1, r5, CLK_RESET_PLLX_MISC3, CLK_RESET_PLLX_MISC3_IDDQ 673*4882a593Smuzhiyun_no_pll_in_iddq: 674*4882a593Smuzhiyun 675*4882a593Smuzhiyun /* 676*4882a593Smuzhiyun * Switch to clk_s (32KHz); bits 28:31=0 677*4882a593Smuzhiyun * Enable burst on CPU IRQ; bit 24=1 678*4882a593Smuzhiyun * Set IRQ burst clock source to clk_m; bits 10:8=0 679*4882a593Smuzhiyun */ 680*4882a593Smuzhiyun mov r0, #(1 << 24) 681*4882a593Smuzhiyun str r0, [r5, #CLK_RESET_SCLK_BURST] 682*4882a593Smuzhiyun 683*4882a593Smuzhiyun ret lr 684*4882a593Smuzhiyun 685*4882a593Smuzhiyun/* 686*4882a593Smuzhiyun * tegra30_enter_sleep 687*4882a593Smuzhiyun * 688*4882a593Smuzhiyun * uses flow controller to enter sleep state 689*4882a593Smuzhiyun * executes from IRAM with SDRAM in selfrefresh when target state is LP0 or LP1 690*4882a593Smuzhiyun * executes from SDRAM with target state is LP2 691*4882a593Smuzhiyun * r6 = TEGRA_FLOW_CTRL_BASE 692*4882a593Smuzhiyun */ 693*4882a593Smuzhiyuntegra30_enter_sleep: 694*4882a593Smuzhiyun cpu_id r1 695*4882a593Smuzhiyun 696*4882a593Smuzhiyun cpu_to_csr_reg r2, r1 697*4882a593Smuzhiyun ldr r0, [r6, r2] 698*4882a593Smuzhiyun orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG 699*4882a593Smuzhiyun orr r0, r0, #FLOW_CTRL_CSR_ENABLE 700*4882a593Smuzhiyun str r0, [r6, r2] 701*4882a593Smuzhiyun 702*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_BASE, r10 703*4882a593Smuzhiyun cmp r10, #TEGRA30 704*4882a593Smuzhiyun mov r0, #FLOW_CTRL_WAIT_FOR_INTERRUPT 705*4882a593Smuzhiyun orreq r0, r0, #FLOW_CTRL_HALT_CPU_IRQ | FLOW_CTRL_HALT_CPU_FIQ 706*4882a593Smuzhiyun orrne r0, r0, #FLOW_CTRL_HALT_LIC_IRQ | FLOW_CTRL_HALT_LIC_FIQ 707*4882a593Smuzhiyun 708*4882a593Smuzhiyun cpu_to_halt_reg r2, r1 709*4882a593Smuzhiyun str r0, [r6, r2] 710*4882a593Smuzhiyun dsb 711*4882a593Smuzhiyun ldr r0, [r6, r2] /* memory barrier */ 712*4882a593Smuzhiyun 713*4882a593Smuzhiyun cmp r10, #TEGRA30 714*4882a593Smuzhiyunhalted: 715*4882a593Smuzhiyun isb 716*4882a593Smuzhiyun dsb 717*4882a593Smuzhiyun wfine /* CPU should be power gated here */ 718*4882a593Smuzhiyun wfeeq 719*4882a593Smuzhiyun 720*4882a593Smuzhiyun /* !!!FIXME!!! Implement halt failure handler */ 721*4882a593Smuzhiyun b halted 722*4882a593Smuzhiyun 723*4882a593Smuzhiyun/* 724*4882a593Smuzhiyun * tegra30_sdram_self_refresh 725*4882a593Smuzhiyun * 726*4882a593Smuzhiyun * called with MMU off and caches disabled 727*4882a593Smuzhiyun * must be executed from IRAM 728*4882a593Smuzhiyun * r4 = TEGRA_PMC_BASE 729*4882a593Smuzhiyun * r5 = TEGRA_CLK_RESET_BASE 730*4882a593Smuzhiyun * r6 = TEGRA_FLOW_CTRL_BASE 731*4882a593Smuzhiyun * r7 = TEGRA_TMRUS_BASE 732*4882a593Smuzhiyun * r10= SoC ID 733*4882a593Smuzhiyun */ 734*4882a593Smuzhiyuntegra30_sdram_self_refresh: 735*4882a593Smuzhiyun 736*4882a593Smuzhiyun adr r8, tegra_sdram_pad_save 737*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_BASE, r10 738*4882a593Smuzhiyun cmp r10, #TEGRA30 739*4882a593Smuzhiyun adreq r2, tegra30_sdram_pad_address 740*4882a593Smuzhiyun ldreq r3, tegra30_sdram_pad_size 741*4882a593Smuzhiyun cmp r10, #TEGRA114 742*4882a593Smuzhiyun adreq r2, tegra114_sdram_pad_address 743*4882a593Smuzhiyun ldreq r3, tegra114_sdram_pad_size 744*4882a593Smuzhiyun cmp r10, #TEGRA124 745*4882a593Smuzhiyun adreq r2, tegra124_sdram_pad_address 746*4882a593Smuzhiyun ldreq r3, tegra30_sdram_pad_size 747*4882a593Smuzhiyun 748*4882a593Smuzhiyun mov r9, #0 749*4882a593Smuzhiyun 750*4882a593Smuzhiyunpadsave: 751*4882a593Smuzhiyun ldr r0, [r2, r9] @ r0 is the addr in the pad_address 752*4882a593Smuzhiyun 753*4882a593Smuzhiyun ldr r1, [r0] 754*4882a593Smuzhiyun str r1, [r8, r9] @ save the content of the addr 755*4882a593Smuzhiyun 756*4882a593Smuzhiyun add r9, r9, #4 757*4882a593Smuzhiyun cmp r3, r9 758*4882a593Smuzhiyun bne padsave 759*4882a593Smuzhiyunpadsave_done: 760*4882a593Smuzhiyun 761*4882a593Smuzhiyun dsb 762*4882a593Smuzhiyun 763*4882a593Smuzhiyun cmp r10, #TEGRA30 764*4882a593Smuzhiyun ldreq r0, =TEGRA_EMC_BASE @ r0 reserved for emc base addr 765*4882a593Smuzhiyun cmp r10, #TEGRA114 766*4882a593Smuzhiyun ldreq r0, =TEGRA_EMC0_BASE 767*4882a593Smuzhiyun cmp r10, #TEGRA124 768*4882a593Smuzhiyun ldreq r0, =TEGRA124_EMC_BASE 769*4882a593Smuzhiyun 770*4882a593Smuzhiyunenter_self_refresh: 771*4882a593Smuzhiyun cmp r10, #TEGRA30 772*4882a593Smuzhiyun mov r1, #0 773*4882a593Smuzhiyun str r1, [r0, #EMC_ZCAL_INTERVAL] 774*4882a593Smuzhiyun str r1, [r0, #EMC_AUTO_CAL_INTERVAL] 775*4882a593Smuzhiyun ldr r1, [r0, #EMC_CFG] 776*4882a593Smuzhiyun bic r1, r1, #(1 << 28) 777*4882a593Smuzhiyun bicne r1, r1, #(1 << 29) 778*4882a593Smuzhiyun str r1, [r0, #EMC_CFG] @ disable DYN_SELF_REF 779*4882a593Smuzhiyun 780*4882a593Smuzhiyun emc_timing_update r1, r0 781*4882a593Smuzhiyun 782*4882a593Smuzhiyun ldr r1, [r7] 783*4882a593Smuzhiyun add r1, r1, #5 784*4882a593Smuzhiyun wait_until r1, r7, r2 785*4882a593Smuzhiyun 786*4882a593Smuzhiyunemc_wait_auto_cal: 787*4882a593Smuzhiyun ldr r1, [r0, #EMC_AUTO_CAL_STATUS] 788*4882a593Smuzhiyun tst r1, #(1 << 31) @ wait until AUTO_CAL_ACTIVE is cleared 789*4882a593Smuzhiyun bne emc_wait_auto_cal 790*4882a593Smuzhiyun 791*4882a593Smuzhiyun mov r1, #3 792*4882a593Smuzhiyun str r1, [r0, #EMC_REQ_CTRL] @ stall incoming DRAM requests 793*4882a593Smuzhiyun 794*4882a593Smuzhiyunemcidle: 795*4882a593Smuzhiyun ldr r1, [r0, #EMC_EMC_STATUS] 796*4882a593Smuzhiyun tst r1, #4 797*4882a593Smuzhiyun beq emcidle 798*4882a593Smuzhiyun 799*4882a593Smuzhiyun mov r1, #1 800*4882a593Smuzhiyun str r1, [r0, #EMC_SELF_REF] 801*4882a593Smuzhiyun 802*4882a593Smuzhiyun emc_device_mask r1, r0 803*4882a593Smuzhiyun 804*4882a593Smuzhiyunemcself: 805*4882a593Smuzhiyun ldr r2, [r0, #EMC_EMC_STATUS] 806*4882a593Smuzhiyun and r2, r2, r1 807*4882a593Smuzhiyun cmp r2, r1 808*4882a593Smuzhiyun bne emcself @ loop until DDR in self-refresh 809*4882a593Smuzhiyun 810*4882a593Smuzhiyun /* Put VTTGEN in the lowest power mode */ 811*4882a593Smuzhiyun ldr r1, [r0, #EMC_XM2VTTGENPADCTRL] 812*4882a593Smuzhiyun mov32 r2, 0xF8F8FFFF @ clear XM2VTTGEN_DRVUP and XM2VTTGEN_DRVDN 813*4882a593Smuzhiyun and r1, r1, r2 814*4882a593Smuzhiyun str r1, [r0, #EMC_XM2VTTGENPADCTRL] 815*4882a593Smuzhiyun ldr r1, [r0, #EMC_XM2VTTGENPADCTRL2] 816*4882a593Smuzhiyun cmp r10, #TEGRA30 817*4882a593Smuzhiyun orreq r1, r1, #7 @ set E_NO_VTTGEN 818*4882a593Smuzhiyun orrne r1, r1, #0x3f 819*4882a593Smuzhiyun str r1, [r0, #EMC_XM2VTTGENPADCTRL2] 820*4882a593Smuzhiyun 821*4882a593Smuzhiyun emc_timing_update r1, r0 822*4882a593Smuzhiyun 823*4882a593Smuzhiyun /* Tegra114 had dual EMC channel, now config the other one */ 824*4882a593Smuzhiyun cmp r10, #TEGRA114 825*4882a593Smuzhiyun bne no_dual_emc_chanl 826*4882a593Smuzhiyun mov32 r1, TEGRA_EMC1_BASE 827*4882a593Smuzhiyun cmp r0, r1 828*4882a593Smuzhiyun movne r0, r1 829*4882a593Smuzhiyun bne enter_self_refresh 830*4882a593Smuzhiyunno_dual_emc_chanl: 831*4882a593Smuzhiyun 832*4882a593Smuzhiyun ldr r1, [r4, #PMC_CTRL] 833*4882a593Smuzhiyun tst r1, #PMC_CTRL_SIDE_EFFECT_LP0 834*4882a593Smuzhiyun bne pmc_io_dpd_skip 835*4882a593Smuzhiyun /* 836*4882a593Smuzhiyun * Put DDR_DATA, DISC_ADDR_CMD, DDR_ADDR_CMD, POP_ADDR_CMD, POP_CLK 837*4882a593Smuzhiyun * and COMP in the lowest power mode when LP1. 838*4882a593Smuzhiyun */ 839*4882a593Smuzhiyun mov32 r1, 0x8EC00000 840*4882a593Smuzhiyun str r1, [r4, #PMC_IO_DPD_REQ] 841*4882a593Smuzhiyunpmc_io_dpd_skip: 842*4882a593Smuzhiyun 843*4882a593Smuzhiyun dsb 844*4882a593Smuzhiyun 845*4882a593Smuzhiyun ret lr 846*4882a593Smuzhiyun 847*4882a593Smuzhiyun .ltorg 848*4882a593Smuzhiyun/* dummy symbol for end of IRAM */ 849*4882a593Smuzhiyun .align L1_CACHE_SHIFT 850*4882a593Smuzhiyun .global tegra30_iram_end 851*4882a593Smuzhiyuntegra30_iram_end: 852*4882a593Smuzhiyun b . 853*4882a593Smuzhiyun#endif 854