1*08438e24SVarun Wadekar /* 2*08438e24SVarun Wadekar * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3*08438e24SVarun Wadekar * 4*08438e24SVarun Wadekar * Redistribution and use in source and binary forms, with or without 5*08438e24SVarun Wadekar * modification, are permitted provided that the following conditions are met: 6*08438e24SVarun Wadekar * 7*08438e24SVarun Wadekar * Redistributions of source code must retain the above copyright notice, this 8*08438e24SVarun Wadekar * list of conditions and the following disclaimer. 9*08438e24SVarun Wadekar * 10*08438e24SVarun Wadekar * Redistributions in binary form must reproduce the above copyright notice, 11*08438e24SVarun Wadekar * this list of conditions and the following disclaimer in the documentation 12*08438e24SVarun Wadekar * and/or other materials provided with the distribution. 13*08438e24SVarun Wadekar * 14*08438e24SVarun Wadekar * Neither the name of ARM nor the names of its contributors may be used 15*08438e24SVarun Wadekar * to endorse or promote products derived from this software without specific 16*08438e24SVarun Wadekar * prior written permission. 17*08438e24SVarun Wadekar * 18*08438e24SVarun Wadekar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*08438e24SVarun Wadekar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*08438e24SVarun Wadekar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*08438e24SVarun Wadekar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*08438e24SVarun Wadekar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*08438e24SVarun Wadekar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*08438e24SVarun Wadekar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*08438e24SVarun Wadekar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*08438e24SVarun Wadekar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*08438e24SVarun Wadekar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*08438e24SVarun Wadekar * POSSIBILITY OF SUCH DAMAGE. 29*08438e24SVarun Wadekar */ 30*08438e24SVarun Wadekar 31*08438e24SVarun Wadekar #include <arch_helpers.h> 32*08438e24SVarun Wadekar #include <assert.h> 33*08438e24SVarun Wadekar #include <bl_common.h> 34*08438e24SVarun Wadekar #include <context.h> 35*08438e24SVarun Wadekar #include <context_mgmt.h> 36*08438e24SVarun Wadekar #include <debug.h> 37*08438e24SVarun Wadekar #include <memctrl.h> 38*08438e24SVarun Wadekar #include <mmio.h> 39*08438e24SVarun Wadekar #include <platform.h> 40*08438e24SVarun Wadekar #include <platform_def.h> 41*08438e24SVarun Wadekar #include <pmc.h> 42*08438e24SVarun Wadekar #include <psci.h> 43*08438e24SVarun Wadekar #include <tegra_def.h> 44*08438e24SVarun Wadekar #include <tegra_private.h> 45*08438e24SVarun Wadekar 46*08438e24SVarun Wadekar extern uint64_t tegra_bl31_phys_base; 47*08438e24SVarun Wadekar extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT]; 48*08438e24SVarun Wadekar static int system_suspended; 49*08438e24SVarun Wadekar 50*08438e24SVarun Wadekar /* 51*08438e24SVarun Wadekar * The following platform setup functions are weakly defined. They 52*08438e24SVarun Wadekar * provide typical implementations that will be overridden by a SoC. 53*08438e24SVarun Wadekar */ 54*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_suspend 55*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_on 56*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_off 57*08438e24SVarun Wadekar #pragma weak tegra_prepare_cpu_on_finish 58*08438e24SVarun Wadekar 59*08438e24SVarun Wadekar int tegra_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) 60*08438e24SVarun Wadekar { 61*08438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 62*08438e24SVarun Wadekar } 63*08438e24SVarun Wadekar 64*08438e24SVarun Wadekar int tegra_prepare_cpu_on(unsigned long mpidr) 65*08438e24SVarun Wadekar { 66*08438e24SVarun Wadekar return PSCI_E_SUCCESS; 67*08438e24SVarun Wadekar } 68*08438e24SVarun Wadekar 69*08438e24SVarun Wadekar int tegra_prepare_cpu_off(unsigned long mpidr) 70*08438e24SVarun Wadekar { 71*08438e24SVarun Wadekar return PSCI_E_SUCCESS; 72*08438e24SVarun Wadekar } 73*08438e24SVarun Wadekar 74*08438e24SVarun Wadekar int tegra_prepare_cpu_on_finish(unsigned long mpidr) 75*08438e24SVarun Wadekar { 76*08438e24SVarun Wadekar return PSCI_E_SUCCESS; 77*08438e24SVarun Wadekar } 78*08438e24SVarun Wadekar 79*08438e24SVarun Wadekar /******************************************************************************* 80*08438e24SVarun Wadekar * Track system suspend entry. 81*08438e24SVarun Wadekar ******************************************************************************/ 82*08438e24SVarun Wadekar void tegra_pm_system_suspend_entry(void) 83*08438e24SVarun Wadekar { 84*08438e24SVarun Wadekar system_suspended = 1; 85*08438e24SVarun Wadekar } 86*08438e24SVarun Wadekar 87*08438e24SVarun Wadekar /******************************************************************************* 88*08438e24SVarun Wadekar * Track system suspend exit. 89*08438e24SVarun Wadekar ******************************************************************************/ 90*08438e24SVarun Wadekar void tegra_pm_system_suspend_exit(void) 91*08438e24SVarun Wadekar { 92*08438e24SVarun Wadekar system_suspended = 0; 93*08438e24SVarun Wadekar } 94*08438e24SVarun Wadekar 95*08438e24SVarun Wadekar /******************************************************************************* 96*08438e24SVarun Wadekar * Get the system suspend state. 97*08438e24SVarun Wadekar ******************************************************************************/ 98*08438e24SVarun Wadekar int tegra_system_suspended(void) 99*08438e24SVarun Wadekar { 100*08438e24SVarun Wadekar return system_suspended; 101*08438e24SVarun Wadekar } 102*08438e24SVarun Wadekar 103*08438e24SVarun Wadekar /******************************************************************************* 104*08438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 105*08438e24SVarun Wadekar ******************************************************************************/ 106*08438e24SVarun Wadekar void tegra_affinst_standby(unsigned int power_state) 107*08438e24SVarun Wadekar { 108*08438e24SVarun Wadekar /* 109*08438e24SVarun Wadekar * Enter standby state 110*08438e24SVarun Wadekar * dsb is good practice before using wfi to enter low power states 111*08438e24SVarun Wadekar */ 112*08438e24SVarun Wadekar dsb(); 113*08438e24SVarun Wadekar wfi(); 114*08438e24SVarun Wadekar } 115*08438e24SVarun Wadekar 116*08438e24SVarun Wadekar /******************************************************************************* 117*08438e24SVarun Wadekar * Handler called to check the validity of the power state parameter. 118*08438e24SVarun Wadekar ******************************************************************************/ 119*08438e24SVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state) 120*08438e24SVarun Wadekar { 121*08438e24SVarun Wadekar /* Sanity check the requested state */ 122*08438e24SVarun Wadekar if (psci_get_pstate_type(power_state) == PSTATE_TYPE_STANDBY) { 123*08438e24SVarun Wadekar /* 124*08438e24SVarun Wadekar * It's possible to enter standby only on affinity level 0 i.e. 125*08438e24SVarun Wadekar * a cpu on Tegra. Ignore any other affinity level. 126*08438e24SVarun Wadekar */ 127*08438e24SVarun Wadekar if (psci_get_pstate_afflvl(power_state) != MPIDR_AFFLVL0) 128*08438e24SVarun Wadekar return PSCI_E_INVALID_PARAMS; 129*08438e24SVarun Wadekar } 130*08438e24SVarun Wadekar 131*08438e24SVarun Wadekar return PSCI_E_SUCCESS; 132*08438e24SVarun Wadekar } 133*08438e24SVarun Wadekar 134*08438e24SVarun Wadekar /******************************************************************************* 135*08438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 136*08438e24SVarun Wadekar * level and mpidr determine the affinity instance. 137*08438e24SVarun Wadekar ******************************************************************************/ 138*08438e24SVarun Wadekar int tegra_affinst_on(unsigned long mpidr, 139*08438e24SVarun Wadekar unsigned long sec_entrypoint, 140*08438e24SVarun Wadekar unsigned int afflvl, 141*08438e24SVarun Wadekar unsigned int state) 142*08438e24SVarun Wadekar { 143*08438e24SVarun Wadekar int cpu = mpidr & MPIDR_CPU_MASK; 144*08438e24SVarun Wadekar 145*08438e24SVarun Wadekar /* 146*08438e24SVarun Wadekar * Support individual CPU power on only. 147*08438e24SVarun Wadekar */ 148*08438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 149*08438e24SVarun Wadekar return PSCI_E_SUCCESS; 150*08438e24SVarun Wadekar 151*08438e24SVarun Wadekar /* 152*08438e24SVarun Wadekar * Flush entrypoint variable to PoC since it will be 153*08438e24SVarun Wadekar * accessed after a reset with the caches turned off. 154*08438e24SVarun Wadekar */ 155*08438e24SVarun Wadekar sec_entry_point[cpu] = sec_entrypoint; 156*08438e24SVarun Wadekar flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); 157*08438e24SVarun Wadekar 158*08438e24SVarun Wadekar return tegra_prepare_cpu_on(mpidr); 159*08438e24SVarun Wadekar } 160*08438e24SVarun Wadekar 161*08438e24SVarun Wadekar /******************************************************************************* 162*08438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned off. The 163*08438e24SVarun Wadekar * level determines the affinity instance. The 'state' arg. allows the 164*08438e24SVarun Wadekar * platform to decide whether the cluster is being turned off and take apt 165*08438e24SVarun Wadekar * actions. 166*08438e24SVarun Wadekar * 167*08438e24SVarun Wadekar * CAUTION: This function is called with coherent stacks so that caches can be 168*08438e24SVarun Wadekar * turned off, flushed and coherency disabled. There is no guarantee that caches 169*08438e24SVarun Wadekar * will remain turned on across calls to this function as each affinity level is 170*08438e24SVarun Wadekar * dealt with. So do not write & read global variables across calls. It will be 171*08438e24SVarun Wadekar * wise to do flush a write to the global to prevent unpredictable results. 172*08438e24SVarun Wadekar ******************************************************************************/ 173*08438e24SVarun Wadekar void tegra_affinst_off(unsigned int afflvl, unsigned int state) 174*08438e24SVarun Wadekar { 175*08438e24SVarun Wadekar /* 176*08438e24SVarun Wadekar * Support individual CPU power off only. 177*08438e24SVarun Wadekar */ 178*08438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 179*08438e24SVarun Wadekar return; 180*08438e24SVarun Wadekar 181*08438e24SVarun Wadekar tegra_prepare_cpu_off(read_mpidr()); 182*08438e24SVarun Wadekar } 183*08438e24SVarun Wadekar 184*08438e24SVarun Wadekar /******************************************************************************* 185*08438e24SVarun Wadekar * Handler called when an affinity instance is about to be suspended. The 186*08438e24SVarun Wadekar * level and mpidr determine the affinity instance. The 'state' arg. allows the 187*08438e24SVarun Wadekar * platform to decide whether the cluster is being turned off and take apt 188*08438e24SVarun Wadekar * actions. 189*08438e24SVarun Wadekar * 190*08438e24SVarun Wadekar * CAUTION: This function is called with coherent stacks so that caches can be 191*08438e24SVarun Wadekar * turned off, flushed and coherency disabled. There is no guarantee that caches 192*08438e24SVarun Wadekar * will remain turned on across calls to this function as each affinity level is 193*08438e24SVarun Wadekar * dealt with. So do not write & read global variables across calls. It will be 194*08438e24SVarun Wadekar * wise to flush a write to the global variable, to prevent unpredictable 195*08438e24SVarun Wadekar * results. 196*08438e24SVarun Wadekar ******************************************************************************/ 197*08438e24SVarun Wadekar void tegra_affinst_suspend(unsigned long sec_entrypoint, 198*08438e24SVarun Wadekar unsigned int afflvl, 199*08438e24SVarun Wadekar unsigned int state) 200*08438e24SVarun Wadekar { 201*08438e24SVarun Wadekar int id = psci_get_suspend_stateid(); 202*08438e24SVarun Wadekar int cpu = read_mpidr() & MPIDR_CPU_MASK; 203*08438e24SVarun Wadekar 204*08438e24SVarun Wadekar if (afflvl > PLATFORM_MAX_AFFLVL) 205*08438e24SVarun Wadekar return; 206*08438e24SVarun Wadekar 207*08438e24SVarun Wadekar /* 208*08438e24SVarun Wadekar * Flush entrypoint variable to PoC since it will be 209*08438e24SVarun Wadekar * accessed after a reset with the caches turned off. 210*08438e24SVarun Wadekar */ 211*08438e24SVarun Wadekar sec_entry_point[cpu] = sec_entrypoint; 212*08438e24SVarun Wadekar flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); 213*08438e24SVarun Wadekar 214*08438e24SVarun Wadekar tegra_prepare_cpu_suspend(id, afflvl); 215*08438e24SVarun Wadekar 216*08438e24SVarun Wadekar /* disable GICC */ 217*08438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 218*08438e24SVarun Wadekar } 219*08438e24SVarun Wadekar 220*08438e24SVarun Wadekar /******************************************************************************* 221*08438e24SVarun Wadekar * Handler called when an affinity instance has just been powered on after 222*08438e24SVarun Wadekar * being turned off earlier. The level determines the affinity instance. 223*08438e24SVarun Wadekar * The 'state' arg. allows the platform to decide whether the cluster was 224*08438e24SVarun Wadekar * turned off prior to wakeup and do what's necessary to set it up. 225*08438e24SVarun Wadekar ******************************************************************************/ 226*08438e24SVarun Wadekar void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) 227*08438e24SVarun Wadekar { 228*08438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 229*08438e24SVarun Wadekar 230*08438e24SVarun Wadekar /* 231*08438e24SVarun Wadekar * Support individual CPU power on only. 232*08438e24SVarun Wadekar */ 233*08438e24SVarun Wadekar if (afflvl > MPIDR_AFFLVL0) 234*08438e24SVarun Wadekar return; 235*08438e24SVarun Wadekar 236*08438e24SVarun Wadekar /* 237*08438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 238*08438e24SVarun Wadekar */ 239*08438e24SVarun Wadekar tegra_gic_setup(); 240*08438e24SVarun Wadekar 241*08438e24SVarun Wadekar /* 242*08438e24SVarun Wadekar * Check if we are exiting from deep sleep. 243*08438e24SVarun Wadekar */ 244*08438e24SVarun Wadekar if (tegra_system_suspended()) { 245*08438e24SVarun Wadekar 246*08438e24SVarun Wadekar /* 247*08438e24SVarun Wadekar * Lock scratch registers which hold the CPU vectors. 248*08438e24SVarun Wadekar */ 249*08438e24SVarun Wadekar tegra_pmc_lock_cpu_vectors(); 250*08438e24SVarun Wadekar 251*08438e24SVarun Wadekar /* 252*08438e24SVarun Wadekar * SMMU configuration. 253*08438e24SVarun Wadekar */ 254*08438e24SVarun Wadekar tegra_memctrl_setup(); 255*08438e24SVarun Wadekar 256*08438e24SVarun Wadekar /* 257*08438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 258*08438e24SVarun Wadekar */ 259*08438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 260*08438e24SVarun Wadekar tegra_memctrl_tzdram_setup(tegra_bl31_phys_base, 261*08438e24SVarun Wadekar plat_params->tzdram_size); 262*08438e24SVarun Wadekar } 263*08438e24SVarun Wadekar 264*08438e24SVarun Wadekar /* 265*08438e24SVarun Wadekar * Reset hardware settings. 266*08438e24SVarun Wadekar */ 267*08438e24SVarun Wadekar tegra_prepare_cpu_on_finish(read_mpidr()); 268*08438e24SVarun Wadekar } 269*08438e24SVarun Wadekar 270*08438e24SVarun Wadekar /******************************************************************************* 271*08438e24SVarun Wadekar * Handler called when an affinity instance has just been powered on after 272*08438e24SVarun Wadekar * having been suspended earlier. The level and mpidr determine the affinity 273*08438e24SVarun Wadekar * instance. 274*08438e24SVarun Wadekar ******************************************************************************/ 275*08438e24SVarun Wadekar void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state) 276*08438e24SVarun Wadekar { 277*08438e24SVarun Wadekar if (afflvl == MPIDR_AFFLVL0) 278*08438e24SVarun Wadekar tegra_affinst_on_finish(afflvl, state); 279*08438e24SVarun Wadekar } 280*08438e24SVarun Wadekar 281*08438e24SVarun Wadekar /******************************************************************************* 282*08438e24SVarun Wadekar * Handler called when the system wants to be powered off 283*08438e24SVarun Wadekar ******************************************************************************/ 284*08438e24SVarun Wadekar __dead2 void tegra_system_off(void) 285*08438e24SVarun Wadekar { 286*08438e24SVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 287*08438e24SVarun Wadekar panic(); 288*08438e24SVarun Wadekar } 289*08438e24SVarun Wadekar 290*08438e24SVarun Wadekar /******************************************************************************* 291*08438e24SVarun Wadekar * Handler called when the system wants to be restarted. 292*08438e24SVarun Wadekar ******************************************************************************/ 293*08438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 294*08438e24SVarun Wadekar { 295*08438e24SVarun Wadekar /* 296*08438e24SVarun Wadekar * Program the PMC in order to restart the system. 297*08438e24SVarun Wadekar */ 298*08438e24SVarun Wadekar tegra_pmc_system_reset(); 299*08438e24SVarun Wadekar } 300*08438e24SVarun Wadekar 301*08438e24SVarun Wadekar /******************************************************************************* 302*08438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 303*08438e24SVarun Wadekar ******************************************************************************/ 304*08438e24SVarun Wadekar static const plat_pm_ops_t tegra_plat_pm_ops = { 305*08438e24SVarun Wadekar .affinst_standby = tegra_affinst_standby, 306*08438e24SVarun Wadekar .affinst_on = tegra_affinst_on, 307*08438e24SVarun Wadekar .affinst_off = tegra_affinst_off, 308*08438e24SVarun Wadekar .affinst_suspend = tegra_affinst_suspend, 309*08438e24SVarun Wadekar .affinst_on_finish = tegra_affinst_on_finish, 310*08438e24SVarun Wadekar .affinst_suspend_finish = tegra_affinst_suspend_finish, 311*08438e24SVarun Wadekar .system_off = tegra_system_off, 312*08438e24SVarun Wadekar .system_reset = tegra_system_reset, 313*08438e24SVarun Wadekar .validate_power_state = tegra_validate_power_state 314*08438e24SVarun Wadekar }; 315*08438e24SVarun Wadekar 316*08438e24SVarun Wadekar /******************************************************************************* 317*08438e24SVarun Wadekar * Export the platform specific power ops & initialize the fvp power controller 318*08438e24SVarun Wadekar ******************************************************************************/ 319*08438e24SVarun Wadekar int platform_setup_pm(const plat_pm_ops_t **plat_ops) 320*08438e24SVarun Wadekar { 321*08438e24SVarun Wadekar /* 322*08438e24SVarun Wadekar * Reset hardware settings. 323*08438e24SVarun Wadekar */ 324*08438e24SVarun Wadekar tegra_prepare_cpu_on_finish(read_mpidr()); 325*08438e24SVarun Wadekar 326*08438e24SVarun Wadekar /* 327*08438e24SVarun Wadekar * Initialize PM ops struct 328*08438e24SVarun Wadekar */ 329*08438e24SVarun Wadekar *plat_ops = &tegra_plat_pm_ops; 330*08438e24SVarun Wadekar 331*08438e24SVarun Wadekar return 0; 332*08438e24SVarun Wadekar } 333