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/init.h> 7*4882a593Smuzhiyun#include <linux/linkage.h> 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun#include <soc/tegra/flowctrl.h> 10*4882a593Smuzhiyun#include <soc/tegra/fuse.h> 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun#include <asm/assembler.h> 13*4882a593Smuzhiyun#include <asm/asm-offsets.h> 14*4882a593Smuzhiyun#include <asm/cache.h> 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun#include "iomap.h" 17*4882a593Smuzhiyun#include "reset.h" 18*4882a593Smuzhiyun#include "sleep.h" 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun#define PMC_SCRATCH41 0x140 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun#ifdef CONFIG_PM_SLEEP 23*4882a593Smuzhiyun/* 24*4882a593Smuzhiyun * tegra_resume 25*4882a593Smuzhiyun * 26*4882a593Smuzhiyun * CPU boot vector when restarting the a CPU following 27*4882a593Smuzhiyun * an LP2 transition. Also branched to by LP0 and LP1 resume after 28*4882a593Smuzhiyun * re-enabling sdram. 29*4882a593Smuzhiyun * 30*4882a593Smuzhiyun * r6: SoC ID 31*4882a593Smuzhiyun * r8: CPU part number 32*4882a593Smuzhiyun */ 33*4882a593SmuzhiyunENTRY(tegra_resume) 34*4882a593Smuzhiyun check_cpu_part_num 0xc09, r8, r9 35*4882a593Smuzhiyun bleq v7_invalidate_l1 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun cpu_id r0 38*4882a593Smuzhiyun cmp r0, #0 @ CPU0? 39*4882a593Smuzhiyun THUMB( it ne ) 40*4882a593Smuzhiyun bne cpu_resume @ no 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_BASE, r6 43*4882a593Smuzhiyun /* Are we on Tegra20? */ 44*4882a593Smuzhiyun cmp r6, #TEGRA20 45*4882a593Smuzhiyun beq 1f @ Yes 46*4882a593Smuzhiyun /* Clear the flow controller flags for this CPU. */ 47*4882a593Smuzhiyun cpu_to_csr_reg r3, r0 48*4882a593Smuzhiyun mov32 r2, TEGRA_FLOW_CTRL_BASE 49*4882a593Smuzhiyun ldr r1, [r2, r3] 50*4882a593Smuzhiyun /* Clear event & intr flag */ 51*4882a593Smuzhiyun orr r1, r1, \ 52*4882a593Smuzhiyun #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG 53*4882a593Smuzhiyun movw r0, #0x3FFD @ enable, cluster_switch, immed, bitmaps 54*4882a593Smuzhiyun @ & ext flags for CPU power mgnt 55*4882a593Smuzhiyun bic r1, r1, r0 56*4882a593Smuzhiyun str r1, [r2, r3] 57*4882a593Smuzhiyun1: 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun mov32 r9, 0xc09 60*4882a593Smuzhiyun cmp r8, r9 61*4882a593Smuzhiyun bne end_ca9_scu_l2_resume 62*4882a593Smuzhiyun#ifdef CONFIG_HAVE_ARM_SCU 63*4882a593Smuzhiyun /* enable SCU */ 64*4882a593Smuzhiyun mov32 r0, TEGRA_ARM_PERIF_BASE 65*4882a593Smuzhiyun ldr r1, [r0] 66*4882a593Smuzhiyun orr r1, r1, #1 67*4882a593Smuzhiyun str r1, [r0] 68*4882a593Smuzhiyun#endif 69*4882a593Smuzhiyun bl tegra_resume_trusted_foundations 70*4882a593Smuzhiyun 71*4882a593Smuzhiyun#ifdef CONFIG_CACHE_L2X0 72*4882a593Smuzhiyun /* L2 cache resume & re-enable */ 73*4882a593Smuzhiyun bl l2c310_early_resume 74*4882a593Smuzhiyun#endif 75*4882a593Smuzhiyunend_ca9_scu_l2_resume: 76*4882a593Smuzhiyun mov32 r9, 0xc0f 77*4882a593Smuzhiyun cmp r8, r9 78*4882a593Smuzhiyun bleq tegra_init_l2_for_a15 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun b cpu_resume 81*4882a593SmuzhiyunENDPROC(tegra_resume) 82*4882a593Smuzhiyun 83*4882a593Smuzhiyun/* 84*4882a593Smuzhiyun * tegra_resume_trusted_foundations 85*4882a593Smuzhiyun * 86*4882a593Smuzhiyun * Trusted Foundations firmware initialization. 87*4882a593Smuzhiyun * 88*4882a593Smuzhiyun * Doesn't return if firmware presents. 89*4882a593Smuzhiyun * Corrupted registers: r1, r2 90*4882a593Smuzhiyun */ 91*4882a593SmuzhiyunENTRY(tegra_resume_trusted_foundations) 92*4882a593Smuzhiyun /* Check whether Trusted Foundations firmware presents. */ 93*4882a593Smuzhiyun mov32 r2, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET 94*4882a593Smuzhiyun ldr r1, =__tegra_cpu_reset_handler_data_offset + \ 95*4882a593Smuzhiyun RESET_DATA(TF_PRESENT) 96*4882a593Smuzhiyun ldr r1, [r2, r1] 97*4882a593Smuzhiyun cmp r1, #0 98*4882a593Smuzhiyun reteq lr 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun .arch_extension sec 101*4882a593Smuzhiyun /* 102*4882a593Smuzhiyun * First call after suspend wakes firmware. No arguments required 103*4882a593Smuzhiyun * for some firmware versions. Downstream kernel of ASUS TF300T uses 104*4882a593Smuzhiyun * r0=3 for the wake-up notification. 105*4882a593Smuzhiyun */ 106*4882a593Smuzhiyun mov r0, #3 107*4882a593Smuzhiyun smc #0 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun b cpu_resume 110*4882a593SmuzhiyunENDPROC(tegra_resume_trusted_foundations) 111*4882a593Smuzhiyun#endif 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun .align L1_CACHE_SHIFT 114*4882a593SmuzhiyunENTRY(__tegra_cpu_reset_handler_start) 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun/* 117*4882a593Smuzhiyun * __tegra_cpu_reset_handler: 118*4882a593Smuzhiyun * 119*4882a593Smuzhiyun * Common handler for all CPU reset events. 120*4882a593Smuzhiyun * 121*4882a593Smuzhiyun * Register usage within the reset handler: 122*4882a593Smuzhiyun * 123*4882a593Smuzhiyun * Others: scratch 124*4882a593Smuzhiyun * R6 = SoC ID 125*4882a593Smuzhiyun * R7 = CPU present (to the OS) mask 126*4882a593Smuzhiyun * R8 = CPU in LP1 state mask 127*4882a593Smuzhiyun * R9 = CPU in LP2 state mask 128*4882a593Smuzhiyun * R10 = CPU number 129*4882a593Smuzhiyun * R11 = CPU mask 130*4882a593Smuzhiyun * R12 = pointer to reset handler data 131*4882a593Smuzhiyun * 132*4882a593Smuzhiyun * NOTE: This code is copied to IRAM. All code and data accesses 133*4882a593Smuzhiyun * must be position-independent. 134*4882a593Smuzhiyun */ 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun .arm 137*4882a593Smuzhiyun .align L1_CACHE_SHIFT 138*4882a593SmuzhiyunENTRY(__tegra_cpu_reset_handler) 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun cpsid aif, 0x13 @ SVC mode, interrupts disabled 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun tegra_get_soc_id TEGRA_APB_MISC_BASE, r6 143*4882a593Smuzhiyun 144*4882a593Smuzhiyun adr r12, __tegra_cpu_reset_handler_data 145*4882a593Smuzhiyun ldr r5, [r12, #RESET_DATA(TF_PRESENT)] 146*4882a593Smuzhiyun cmp r5, #0 147*4882a593Smuzhiyun bne after_errata 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun#ifdef CONFIG_ARCH_TEGRA_2x_SOC 150*4882a593Smuzhiyunt20_check: 151*4882a593Smuzhiyun cmp r6, #TEGRA20 152*4882a593Smuzhiyun bne after_t20_check 153*4882a593Smuzhiyunt20_errata: 154*4882a593Smuzhiyun # Tegra20 is a Cortex-A9 r1p1 155*4882a593Smuzhiyun mrc p15, 0, r0, c1, c0, 0 @ read system control register 156*4882a593Smuzhiyun orr r0, r0, #1 << 14 @ erratum 716044 157*4882a593Smuzhiyun mcr p15, 0, r0, c1, c0, 0 @ write system control register 158*4882a593Smuzhiyun mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register 159*4882a593Smuzhiyun orr r0, r0, #1 << 4 @ erratum 742230 160*4882a593Smuzhiyun orr r0, r0, #1 << 11 @ erratum 751472 161*4882a593Smuzhiyun mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register 162*4882a593Smuzhiyun b after_errata 163*4882a593Smuzhiyunafter_t20_check: 164*4882a593Smuzhiyun#endif 165*4882a593Smuzhiyun#ifdef CONFIG_ARCH_TEGRA_3x_SOC 166*4882a593Smuzhiyunt30_check: 167*4882a593Smuzhiyun cmp r6, #TEGRA30 168*4882a593Smuzhiyun bne after_t30_check 169*4882a593Smuzhiyunt30_errata: 170*4882a593Smuzhiyun # Tegra30 is a Cortex-A9 r2p9 171*4882a593Smuzhiyun mrc p15, 0, r0, c15, c0, 1 @ read diagnostic register 172*4882a593Smuzhiyun orr r0, r0, #1 << 6 @ erratum 743622 173*4882a593Smuzhiyun orr r0, r0, #1 << 11 @ erratum 751472 174*4882a593Smuzhiyun mcr p15, 0, r0, c15, c0, 1 @ write diagnostic register 175*4882a593Smuzhiyun b after_errata 176*4882a593Smuzhiyunafter_t30_check: 177*4882a593Smuzhiyun#endif 178*4882a593Smuzhiyunafter_errata: 179*4882a593Smuzhiyun mrc p15, 0, r10, c0, c0, 5 @ MPIDR 180*4882a593Smuzhiyun and r10, r10, #0x3 @ R10 = CPU number 181*4882a593Smuzhiyun mov r11, #1 182*4882a593Smuzhiyun mov r11, r11, lsl r10 @ R11 = CPU mask 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun#ifdef CONFIG_SMP 185*4882a593Smuzhiyun /* Does the OS know about this CPU? */ 186*4882a593Smuzhiyun ldr r7, [r12, #RESET_DATA(MASK_PRESENT)] 187*4882a593Smuzhiyun tst r7, r11 @ if !present 188*4882a593Smuzhiyun bleq __die @ CPU not present (to OS) 189*4882a593Smuzhiyun#endif 190*4882a593Smuzhiyun 191*4882a593Smuzhiyun /* Waking up from LP1? */ 192*4882a593Smuzhiyun ldr r8, [r12, #RESET_DATA(MASK_LP1)] 193*4882a593Smuzhiyun tst r8, r11 @ if in_lp1 194*4882a593Smuzhiyun beq __is_not_lp1 195*4882a593Smuzhiyun cmp r10, #0 196*4882a593Smuzhiyun bne __die @ only CPU0 can be here 197*4882a593Smuzhiyun ldr lr, [r12, #RESET_DATA(STARTUP_LP1)] 198*4882a593Smuzhiyun cmp lr, #0 199*4882a593Smuzhiyun bleq __die @ no LP1 startup handler 200*4882a593Smuzhiyun THUMB( add lr, lr, #1 ) @ switch to Thumb mode 201*4882a593Smuzhiyun bx lr 202*4882a593Smuzhiyun__is_not_lp1: 203*4882a593Smuzhiyun 204*4882a593Smuzhiyun /* Waking up from LP2? */ 205*4882a593Smuzhiyun ldr r9, [r12, #RESET_DATA(MASK_LP2)] 206*4882a593Smuzhiyun tst r9, r11 @ if in_lp2 207*4882a593Smuzhiyun beq __is_not_lp2 208*4882a593Smuzhiyun ldr lr, [r12, #RESET_DATA(STARTUP_LP2)] 209*4882a593Smuzhiyun cmp lr, #0 210*4882a593Smuzhiyun bleq __die @ no LP2 startup handler 211*4882a593Smuzhiyun bx lr 212*4882a593Smuzhiyun 213*4882a593Smuzhiyun__is_not_lp2: 214*4882a593Smuzhiyun 215*4882a593Smuzhiyun#ifdef CONFIG_SMP 216*4882a593Smuzhiyun /* 217*4882a593Smuzhiyun * Can only be secondary boot (initial or hotplug) 218*4882a593Smuzhiyun * CPU0 can't be here for Tegra20/30 219*4882a593Smuzhiyun */ 220*4882a593Smuzhiyun cmp r6, #TEGRA114 221*4882a593Smuzhiyun beq __no_cpu0_chk 222*4882a593Smuzhiyun cmp r10, #0 223*4882a593Smuzhiyun bleq __die @ CPU0 cannot be here 224*4882a593Smuzhiyun__no_cpu0_chk: 225*4882a593Smuzhiyun ldr lr, [r12, #RESET_DATA(STARTUP_SECONDARY)] 226*4882a593Smuzhiyun cmp lr, #0 227*4882a593Smuzhiyun bleq __die @ no secondary startup handler 228*4882a593Smuzhiyun bx lr 229*4882a593Smuzhiyun#endif 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun/* 232*4882a593Smuzhiyun * We don't know why the CPU reset. Just kill it. 233*4882a593Smuzhiyun * The LR register will contain the address we died at + 4. 234*4882a593Smuzhiyun */ 235*4882a593Smuzhiyun 236*4882a593Smuzhiyun__die: 237*4882a593Smuzhiyun sub lr, lr, #4 238*4882a593Smuzhiyun mov32 r7, TEGRA_PMC_BASE 239*4882a593Smuzhiyun str lr, [r7, #PMC_SCRATCH41] 240*4882a593Smuzhiyun 241*4882a593Smuzhiyun mov32 r7, TEGRA_CLK_RESET_BASE 242*4882a593Smuzhiyun 243*4882a593Smuzhiyun /* Are we on Tegra20? */ 244*4882a593Smuzhiyun cmp r6, #TEGRA20 245*4882a593Smuzhiyun bne 1f 246*4882a593Smuzhiyun 247*4882a593Smuzhiyun#ifdef CONFIG_ARCH_TEGRA_2x_SOC 248*4882a593Smuzhiyun mov32 r0, 0x1111 249*4882a593Smuzhiyun mov r1, r0, lsl r10 250*4882a593Smuzhiyun str r1, [r7, #0x340] @ CLK_RST_CPU_CMPLX_SET 251*4882a593Smuzhiyun#endif 252*4882a593Smuzhiyun1: 253*4882a593Smuzhiyun#ifdef CONFIG_ARCH_TEGRA_3x_SOC 254*4882a593Smuzhiyun mov32 r6, TEGRA_FLOW_CTRL_BASE 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun cmp r10, #0 257*4882a593Smuzhiyun moveq r1, #FLOW_CTRL_HALT_CPU0_EVENTS 258*4882a593Smuzhiyun moveq r2, #FLOW_CTRL_CPU0_CSR 259*4882a593Smuzhiyun movne r1, r10, lsl #3 260*4882a593Smuzhiyun addne r2, r1, #(FLOW_CTRL_CPU1_CSR-8) 261*4882a593Smuzhiyun addne r1, r1, #(FLOW_CTRL_HALT_CPU1_EVENTS-8) 262*4882a593Smuzhiyun 263*4882a593Smuzhiyun /* Clear CPU "event" and "interrupt" flags and power gate 264*4882a593Smuzhiyun it when halting but not before it is in the "WFI" state. */ 265*4882a593Smuzhiyun ldr r0, [r6, +r2] 266*4882a593Smuzhiyun orr r0, r0, #FLOW_CTRL_CSR_INTR_FLAG | FLOW_CTRL_CSR_EVENT_FLAG 267*4882a593Smuzhiyun orr r0, r0, #FLOW_CTRL_CSR_ENABLE 268*4882a593Smuzhiyun str r0, [r6, +r2] 269*4882a593Smuzhiyun 270*4882a593Smuzhiyun /* Unconditionally halt this CPU */ 271*4882a593Smuzhiyun mov r0, #FLOW_CTRL_WAITEVENT 272*4882a593Smuzhiyun str r0, [r6, +r1] 273*4882a593Smuzhiyun ldr r0, [r6, +r1] @ memory barrier 274*4882a593Smuzhiyun 275*4882a593Smuzhiyun dsb 276*4882a593Smuzhiyun isb 277*4882a593Smuzhiyun wfi @ CPU should be power gated here 278*4882a593Smuzhiyun 279*4882a593Smuzhiyun /* If the CPU didn't power gate above just kill it's clock. */ 280*4882a593Smuzhiyun 281*4882a593Smuzhiyun mov r0, r11, lsl #8 282*4882a593Smuzhiyun str r0, [r7, #348] @ CLK_CPU_CMPLX_SET 283*4882a593Smuzhiyun#endif 284*4882a593Smuzhiyun 285*4882a593Smuzhiyun /* If the CPU still isn't dead, just spin here. */ 286*4882a593Smuzhiyun b . 287*4882a593SmuzhiyunENDPROC(__tegra_cpu_reset_handler) 288*4882a593Smuzhiyun 289*4882a593Smuzhiyun .align L1_CACHE_SHIFT 290*4882a593Smuzhiyun .type __tegra_cpu_reset_handler_data, %object 291*4882a593Smuzhiyun .globl __tegra_cpu_reset_handler_data 292*4882a593Smuzhiyun .globl __tegra_cpu_reset_handler_data_offset 293*4882a593Smuzhiyun .equ __tegra_cpu_reset_handler_data_offset, \ 294*4882a593Smuzhiyun . - __tegra_cpu_reset_handler_start 295*4882a593Smuzhiyun__tegra_cpu_reset_handler_data: 296*4882a593Smuzhiyun .rept TEGRA_RESET_DATA_SIZE 297*4882a593Smuzhiyun .long 0 298*4882a593Smuzhiyun .endr 299*4882a593Smuzhiyun .align L1_CACHE_SHIFT 300*4882a593Smuzhiyun 301*4882a593SmuzhiyunENTRY(__tegra_cpu_reset_handler_end) 302