1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <arch_helpers.h> 10*91f16700Schasinglulu #include <cortex_a53.h> 11*91f16700Schasinglulu #include <common/debug.h> 12*91f16700Schasinglulu #include <drivers/delay_timer.h> 13*91f16700Schasinglulu #include <lib/mmio.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include <flowctrl.h> 16*91f16700Schasinglulu #include <lib/utils_def.h> 17*91f16700Schasinglulu #include <pmc.h> 18*91f16700Schasinglulu #include <tegra_def.h> 19*91f16700Schasinglulu 20*91f16700Schasinglulu #define CLK_RST_DEV_L_SET 0x300 21*91f16700Schasinglulu #define CLK_RST_DEV_L_CLR 0x304 22*91f16700Schasinglulu #define CLK_BPMP_RST (1 << 1) 23*91f16700Schasinglulu 24*91f16700Schasinglulu #define EVP_BPMP_RESET_VECTOR 0x200 25*91f16700Schasinglulu 26*91f16700Schasinglulu static const uint64_t flowctrl_offset_cpu_csr[4] = { 27*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR), 28*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR), 29*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8), 30*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16) 31*91f16700Schasinglulu }; 32*91f16700Schasinglulu 33*91f16700Schasinglulu static const uint64_t flowctrl_offset_halt_cpu[4] = { 34*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS), 35*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS), 36*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8), 37*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16) 38*91f16700Schasinglulu }; 39*91f16700Schasinglulu 40*91f16700Schasinglulu static const uint64_t flowctrl_offset_cc4_ctrl[4] = { 41*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL), 42*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4), 43*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8), 44*91f16700Schasinglulu (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12) 45*91f16700Schasinglulu }; 46*91f16700Schasinglulu 47*91f16700Schasinglulu static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val) 48*91f16700Schasinglulu { 49*91f16700Schasinglulu mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val); 50*91f16700Schasinglulu val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]); 51*91f16700Schasinglulu } 52*91f16700Schasinglulu 53*91f16700Schasinglulu static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val) 54*91f16700Schasinglulu { 55*91f16700Schasinglulu mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val); 56*91f16700Schasinglulu val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]); 57*91f16700Schasinglulu } 58*91f16700Schasinglulu 59*91f16700Schasinglulu static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val) 60*91f16700Schasinglulu { 61*91f16700Schasinglulu mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val); 62*91f16700Schasinglulu val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]); 63*91f16700Schasinglulu } 64*91f16700Schasinglulu 65*91f16700Schasinglulu static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr) 66*91f16700Schasinglulu { 67*91f16700Schasinglulu uint32_t val; 68*91f16700Schasinglulu 69*91f16700Schasinglulu val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ | 70*91f16700Schasinglulu FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ | 71*91f16700Schasinglulu FLOWCTRL_WAITEVENT; 72*91f16700Schasinglulu tegra_fc_halt_cpu(cpu_id, val); 73*91f16700Schasinglulu 74*91f16700Schasinglulu val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG | 75*91f16700Schasinglulu FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id); 76*91f16700Schasinglulu tegra_fc_cpu_csr(cpu_id, val | csr); 77*91f16700Schasinglulu } 78*91f16700Schasinglulu 79*91f16700Schasinglulu /******************************************************************************* 80*91f16700Schasinglulu * After this, no core can wake from C7 until the action is reverted. 81*91f16700Schasinglulu * If a wake up event is asserted, the FC state machine will stall until 82*91f16700Schasinglulu * the action is reverted. 83*91f16700Schasinglulu ******************************************************************************/ 84*91f16700Schasinglulu void tegra_fc_ccplex_pgexit_lock(void) 85*91f16700Schasinglulu { 86*91f16700Schasinglulu unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK; 87*91f16700Schasinglulu uint32_t flags = tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT) & ~INTERCEPT_IRQ_PENDING; 88*91f16700Schasinglulu uint32_t icept_cpu_flags[] = { 89*91f16700Schasinglulu INTERCEPT_EXIT_PG_CORE0, 90*91f16700Schasinglulu INTERCEPT_EXIT_PG_CORE1, 91*91f16700Schasinglulu INTERCEPT_EXIT_PG_CORE2, 92*91f16700Schasinglulu INTERCEPT_EXIT_PG_CORE3 93*91f16700Schasinglulu }; 94*91f16700Schasinglulu 95*91f16700Schasinglulu /* set the intercept flags */ 96*91f16700Schasinglulu for (i = 0; i < ARRAY_SIZE(icept_cpu_flags); i++) { 97*91f16700Schasinglulu 98*91f16700Schasinglulu /* skip current CPU */ 99*91f16700Schasinglulu if (i == cpu) 100*91f16700Schasinglulu continue; 101*91f16700Schasinglulu 102*91f16700Schasinglulu /* enable power gate exit intercept locks */ 103*91f16700Schasinglulu flags |= icept_cpu_flags[i]; 104*91f16700Schasinglulu } 105*91f16700Schasinglulu 106*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, flags); 107*91f16700Schasinglulu (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT); 108*91f16700Schasinglulu } 109*91f16700Schasinglulu 110*91f16700Schasinglulu /******************************************************************************* 111*91f16700Schasinglulu * Revert the ccplex powergate exit locks 112*91f16700Schasinglulu ******************************************************************************/ 113*91f16700Schasinglulu void tegra_fc_ccplex_pgexit_unlock(void) 114*91f16700Schasinglulu { 115*91f16700Schasinglulu /* clear lock bits, clear pending interrupts */ 116*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, INTERCEPT_IRQ_PENDING); 117*91f16700Schasinglulu (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT); 118*91f16700Schasinglulu } 119*91f16700Schasinglulu 120*91f16700Schasinglulu /******************************************************************************* 121*91f16700Schasinglulu * Powerdn the current CPU 122*91f16700Schasinglulu ******************************************************************************/ 123*91f16700Schasinglulu void tegra_fc_cpu_powerdn(uint32_t mpidr) 124*91f16700Schasinglulu { 125*91f16700Schasinglulu int cpu = mpidr & MPIDR_CPU_MASK; 126*91f16700Schasinglulu 127*91f16700Schasinglulu VERBOSE("CPU%d powering down...\n", cpu); 128*91f16700Schasinglulu tegra_fc_prepare_suspend(cpu, 0); 129*91f16700Schasinglulu } 130*91f16700Schasinglulu 131*91f16700Schasinglulu /******************************************************************************* 132*91f16700Schasinglulu * Suspend the current CPU cluster 133*91f16700Schasinglulu ******************************************************************************/ 134*91f16700Schasinglulu void tegra_fc_cluster_idle(uint32_t mpidr) 135*91f16700Schasinglulu { 136*91f16700Schasinglulu int cpu = mpidr & MPIDR_CPU_MASK; 137*91f16700Schasinglulu uint32_t val; 138*91f16700Schasinglulu 139*91f16700Schasinglulu VERBOSE("Entering cluster idle state...\n"); 140*91f16700Schasinglulu 141*91f16700Schasinglulu tegra_fc_cc4_ctrl(cpu, 0); 142*91f16700Schasinglulu 143*91f16700Schasinglulu /* hardware L2 flush is faster for A53 only */ 144*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 145*91f16700Schasinglulu !!MPIDR_AFFLVL1_VAL(mpidr)); 146*91f16700Schasinglulu 147*91f16700Schasinglulu /* suspend the CPU cluster */ 148*91f16700Schasinglulu val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT; 149*91f16700Schasinglulu tegra_fc_prepare_suspend(cpu, val); 150*91f16700Schasinglulu } 151*91f16700Schasinglulu 152*91f16700Schasinglulu /******************************************************************************* 153*91f16700Schasinglulu * Power down the current CPU cluster 154*91f16700Schasinglulu ******************************************************************************/ 155*91f16700Schasinglulu void tegra_fc_cluster_powerdn(uint32_t mpidr) 156*91f16700Schasinglulu { 157*91f16700Schasinglulu int cpu = mpidr & MPIDR_CPU_MASK; 158*91f16700Schasinglulu uint32_t val; 159*91f16700Schasinglulu 160*91f16700Schasinglulu VERBOSE("Entering cluster powerdn state...\n"); 161*91f16700Schasinglulu 162*91f16700Schasinglulu tegra_fc_cc4_ctrl(cpu, 0); 163*91f16700Schasinglulu 164*91f16700Schasinglulu /* hardware L2 flush is faster for A53 only */ 165*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 166*91f16700Schasinglulu read_midr() == CORTEX_A53_MIDR); 167*91f16700Schasinglulu 168*91f16700Schasinglulu /* power down the CPU cluster */ 169*91f16700Schasinglulu val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT; 170*91f16700Schasinglulu tegra_fc_prepare_suspend(cpu, val); 171*91f16700Schasinglulu } 172*91f16700Schasinglulu 173*91f16700Schasinglulu /******************************************************************************* 174*91f16700Schasinglulu * Check if cluster idle or power down state is allowed from this CPU 175*91f16700Schasinglulu ******************************************************************************/ 176*91f16700Schasinglulu bool tegra_fc_is_ccx_allowed(void) 177*91f16700Schasinglulu { 178*91f16700Schasinglulu unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK; 179*91f16700Schasinglulu uint32_t val; 180*91f16700Schasinglulu bool ccx_allowed = true; 181*91f16700Schasinglulu 182*91f16700Schasinglulu for (i = 0; i < ARRAY_SIZE(flowctrl_offset_cpu_csr); i++) { 183*91f16700Schasinglulu 184*91f16700Schasinglulu /* skip current CPU */ 185*91f16700Schasinglulu if (i == cpu) 186*91f16700Schasinglulu continue; 187*91f16700Schasinglulu 188*91f16700Schasinglulu /* check if all other CPUs are already halted */ 189*91f16700Schasinglulu val = mmio_read_32(flowctrl_offset_cpu_csr[i]); 190*91f16700Schasinglulu if ((val & FLOWCTRL_CSR_HALT_MASK) == 0U) { 191*91f16700Schasinglulu ccx_allowed = false; 192*91f16700Schasinglulu } 193*91f16700Schasinglulu } 194*91f16700Schasinglulu 195*91f16700Schasinglulu return ccx_allowed; 196*91f16700Schasinglulu } 197*91f16700Schasinglulu 198*91f16700Schasinglulu /******************************************************************************* 199*91f16700Schasinglulu * Suspend the entire SoC 200*91f16700Schasinglulu ******************************************************************************/ 201*91f16700Schasinglulu void tegra_fc_soc_powerdn(uint32_t mpidr) 202*91f16700Schasinglulu { 203*91f16700Schasinglulu int cpu = mpidr & MPIDR_CPU_MASK; 204*91f16700Schasinglulu uint32_t val; 205*91f16700Schasinglulu 206*91f16700Schasinglulu VERBOSE("Entering SoC powerdn state...\n"); 207*91f16700Schasinglulu 208*91f16700Schasinglulu tegra_fc_cc4_ctrl(cpu, 0); 209*91f16700Schasinglulu 210*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1); 211*91f16700Schasinglulu 212*91f16700Schasinglulu val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT; 213*91f16700Schasinglulu tegra_fc_prepare_suspend(cpu, val); 214*91f16700Schasinglulu 215*91f16700Schasinglulu /* overwrite HALT register */ 216*91f16700Schasinglulu tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT); 217*91f16700Schasinglulu } 218*91f16700Schasinglulu 219*91f16700Schasinglulu /******************************************************************************* 220*91f16700Schasinglulu * Power up the CPU 221*91f16700Schasinglulu ******************************************************************************/ 222*91f16700Schasinglulu void tegra_fc_cpu_on(int cpu) 223*91f16700Schasinglulu { 224*91f16700Schasinglulu tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE); 225*91f16700Schasinglulu tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK); 226*91f16700Schasinglulu } 227*91f16700Schasinglulu 228*91f16700Schasinglulu /******************************************************************************* 229*91f16700Schasinglulu * Power down the CPU 230*91f16700Schasinglulu ******************************************************************************/ 231*91f16700Schasinglulu void tegra_fc_cpu_off(int cpu) 232*91f16700Schasinglulu { 233*91f16700Schasinglulu uint32_t val; 234*91f16700Schasinglulu 235*91f16700Schasinglulu /* 236*91f16700Schasinglulu * Flow controller powers down the CPU during wfi. The CPU would be 237*91f16700Schasinglulu * powered on when it receives any interrupt. 238*91f16700Schasinglulu */ 239*91f16700Schasinglulu val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG | 240*91f16700Schasinglulu FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu); 241*91f16700Schasinglulu tegra_fc_cpu_csr(cpu, val); 242*91f16700Schasinglulu tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT); 243*91f16700Schasinglulu tegra_fc_cc4_ctrl(cpu, 0); 244*91f16700Schasinglulu } 245*91f16700Schasinglulu 246*91f16700Schasinglulu /******************************************************************************* 247*91f16700Schasinglulu * Inform the BPMP that we have completed the cluster power up 248*91f16700Schasinglulu ******************************************************************************/ 249*91f16700Schasinglulu void tegra_fc_lock_active_cluster(void) 250*91f16700Schasinglulu { 251*91f16700Schasinglulu uint32_t val; 252*91f16700Schasinglulu 253*91f16700Schasinglulu val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL); 254*91f16700Schasinglulu val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK; 255*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val); 256*91f16700Schasinglulu val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL); 257*91f16700Schasinglulu } 258*91f16700Schasinglulu 259*91f16700Schasinglulu /******************************************************************************* 260*91f16700Schasinglulu * Power ON BPMP processor 261*91f16700Schasinglulu ******************************************************************************/ 262*91f16700Schasinglulu void tegra_fc_bpmp_on(uint32_t entrypoint) 263*91f16700Schasinglulu { 264*91f16700Schasinglulu /* halt BPMP */ 265*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); 266*91f16700Schasinglulu 267*91f16700Schasinglulu /* Assert BPMP reset */ 268*91f16700Schasinglulu mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); 269*91f16700Schasinglulu 270*91f16700Schasinglulu /* Set reset address (stored in PMC_SCRATCH39) */ 271*91f16700Schasinglulu mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint); 272*91f16700Schasinglulu while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) 273*91f16700Schasinglulu ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ 274*91f16700Schasinglulu 275*91f16700Schasinglulu /* Wait for 2us before de-asserting the reset signal. */ 276*91f16700Schasinglulu udelay(2); 277*91f16700Schasinglulu 278*91f16700Schasinglulu /* De-assert BPMP reset */ 279*91f16700Schasinglulu mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST); 280*91f16700Schasinglulu 281*91f16700Schasinglulu /* Un-halt BPMP */ 282*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0); 283*91f16700Schasinglulu } 284*91f16700Schasinglulu 285*91f16700Schasinglulu /******************************************************************************* 286*91f16700Schasinglulu * Power OFF BPMP processor 287*91f16700Schasinglulu ******************************************************************************/ 288*91f16700Schasinglulu void tegra_fc_bpmp_off(void) 289*91f16700Schasinglulu { 290*91f16700Schasinglulu /* halt BPMP */ 291*91f16700Schasinglulu tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); 292*91f16700Schasinglulu 293*91f16700Schasinglulu /* Assert BPMP reset */ 294*91f16700Schasinglulu mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); 295*91f16700Schasinglulu 296*91f16700Schasinglulu /* Clear reset address */ 297*91f16700Schasinglulu mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0); 298*91f16700Schasinglulu while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) 299*91f16700Schasinglulu ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ 300*91f16700Schasinglulu } 301*91f16700Schasinglulu 302*91f16700Schasinglulu /******************************************************************************* 303*91f16700Schasinglulu * Route legacy FIQ to the GICD 304*91f16700Schasinglulu ******************************************************************************/ 305*91f16700Schasinglulu void tegra_fc_enable_fiq_to_ccplex_routing(void) 306*91f16700Schasinglulu { 307*91f16700Schasinglulu uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL); 308*91f16700Schasinglulu 309*91f16700Schasinglulu /* set the bit to pass FIQs to the GICD */ 310*91f16700Schasinglulu tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val | FLOWCTRL_FIQ2CCPLEX_ENABLE); 311*91f16700Schasinglulu } 312*91f16700Schasinglulu 313*91f16700Schasinglulu /******************************************************************************* 314*91f16700Schasinglulu * Disable routing legacy FIQ to the GICD 315*91f16700Schasinglulu ******************************************************************************/ 316*91f16700Schasinglulu void tegra_fc_disable_fiq_to_ccplex_routing(void) 317*91f16700Schasinglulu { 318*91f16700Schasinglulu uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL); 319*91f16700Schasinglulu 320*91f16700Schasinglulu /* clear the bit to pass FIQs to the GICD */ 321*91f16700Schasinglulu tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val & ~FLOWCTRL_FIQ2CCPLEX_ENABLE); 322*91f16700Schasinglulu } 323