1*b4315306SDan Handley /* 2*b4315306SDan Handley * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3*b4315306SDan Handley * 4*b4315306SDan Handley * Redistribution and use in source and binary forms, with or without 5*b4315306SDan Handley * modification, are permitted provided that the following conditions are met: 6*b4315306SDan Handley * 7*b4315306SDan Handley * Redistributions of source code must retain the above copyright notice, this 8*b4315306SDan Handley * list of conditions and the following disclaimer. 9*b4315306SDan Handley * 10*b4315306SDan Handley * Redistributions in binary form must reproduce the above copyright notice, 11*b4315306SDan Handley * this list of conditions and the following disclaimer in the documentation 12*b4315306SDan Handley * and/or other materials provided with the distribution. 13*b4315306SDan Handley * 14*b4315306SDan Handley * Neither the name of ARM nor the names of its contributors may be used 15*b4315306SDan Handley * to endorse or promote products derived from this software without specific 16*b4315306SDan Handley * prior written permission. 17*b4315306SDan Handley * 18*b4315306SDan Handley * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*b4315306SDan Handley * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*b4315306SDan Handley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*b4315306SDan Handley * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*b4315306SDan Handley * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*b4315306SDan Handley * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*b4315306SDan Handley * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*b4315306SDan Handley * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*b4315306SDan Handley * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*b4315306SDan Handley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*b4315306SDan Handley * POSSIBILITY OF SUCH DAMAGE. 29*b4315306SDan Handley */ 30*b4315306SDan Handley 31*b4315306SDan Handley #include <assert.h> 32*b4315306SDan Handley #include <arch_helpers.h> 33*b4315306SDan Handley #include <arm_gic.h> 34*b4315306SDan Handley #include <cci.h> 35*b4315306SDan Handley #include <css_def.h> 36*b4315306SDan Handley #include <debug.h> 37*b4315306SDan Handley #include <errno.h> 38*b4315306SDan Handley #include <plat_arm.h> 39*b4315306SDan Handley #include <platform.h> 40*b4315306SDan Handley #include <platform_def.h> 41*b4315306SDan Handley #include <psci.h> 42*b4315306SDan Handley #include "css_scpi.h" 43*b4315306SDan Handley 44*b4315306SDan Handley /******************************************************************************* 45*b4315306SDan Handley * Private function to program the mailbox for a cpu before it is released 46*b4315306SDan Handley * from reset. 47*b4315306SDan Handley ******************************************************************************/ 48*b4315306SDan Handley static void css_program_mailbox(uint64_t mpidr, uint64_t address) 49*b4315306SDan Handley { 50*b4315306SDan Handley uint64_t linear_id; 51*b4315306SDan Handley uint64_t mbox; 52*b4315306SDan Handley 53*b4315306SDan Handley linear_id = platform_get_core_pos(mpidr); 54*b4315306SDan Handley mbox = TRUSTED_MAILBOXES_BASE + (linear_id << TRUSTED_MAILBOX_SHIFT); 55*b4315306SDan Handley *((uint64_t *) mbox) = address; 56*b4315306SDan Handley flush_dcache_range(mbox, sizeof(mbox)); 57*b4315306SDan Handley } 58*b4315306SDan Handley 59*b4315306SDan Handley /******************************************************************************* 60*b4315306SDan Handley * Handler called when an affinity instance is about to be turned on. The 61*b4315306SDan Handley * level and mpidr determine the affinity instance. 62*b4315306SDan Handley ******************************************************************************/ 63*b4315306SDan Handley int32_t css_affinst_on(uint64_t mpidr, 64*b4315306SDan Handley uint64_t sec_entrypoint, 65*b4315306SDan Handley uint32_t afflvl, 66*b4315306SDan Handley uint32_t state) 67*b4315306SDan Handley { 68*b4315306SDan Handley /* 69*b4315306SDan Handley * SCP takes care of powering up higher affinity levels so we 70*b4315306SDan Handley * only need to care about level 0 71*b4315306SDan Handley */ 72*b4315306SDan Handley if (afflvl != MPIDR_AFFLVL0) 73*b4315306SDan Handley return PSCI_E_SUCCESS; 74*b4315306SDan Handley 75*b4315306SDan Handley /* 76*b4315306SDan Handley * Setup mailbox with address for CPU entrypoint when it next powers up 77*b4315306SDan Handley */ 78*b4315306SDan Handley css_program_mailbox(mpidr, sec_entrypoint); 79*b4315306SDan Handley 80*b4315306SDan Handley scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, 81*b4315306SDan Handley scpi_power_on); 82*b4315306SDan Handley 83*b4315306SDan Handley return PSCI_E_SUCCESS; 84*b4315306SDan Handley } 85*b4315306SDan Handley 86*b4315306SDan Handley /******************************************************************************* 87*b4315306SDan Handley * Handler called when an affinity instance has just been powered on after 88*b4315306SDan Handley * being turned off earlier. The level and mpidr determine the affinity 89*b4315306SDan Handley * instance. The 'state' arg. allows the platform to decide whether the cluster 90*b4315306SDan Handley * was turned off prior to wakeup and do what's necessary to setup it up 91*b4315306SDan Handley * correctly. 92*b4315306SDan Handley ******************************************************************************/ 93*b4315306SDan Handley void css_affinst_on_finish(uint32_t afflvl, uint32_t state) 94*b4315306SDan Handley { 95*b4315306SDan Handley unsigned long mpidr; 96*b4315306SDan Handley 97*b4315306SDan Handley /* Determine if any platform actions need to be executed. */ 98*b4315306SDan Handley if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) 99*b4315306SDan Handley return; 100*b4315306SDan Handley 101*b4315306SDan Handley /* Get the mpidr for this cpu */ 102*b4315306SDan Handley mpidr = read_mpidr_el1(); 103*b4315306SDan Handley 104*b4315306SDan Handley /* 105*b4315306SDan Handley * Perform the common cluster specific operations i.e enable coherency 106*b4315306SDan Handley * if this cluster was off. 107*b4315306SDan Handley */ 108*b4315306SDan Handley if (afflvl != MPIDR_AFFLVL0) 109*b4315306SDan Handley cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 110*b4315306SDan Handley 111*b4315306SDan Handley /* Enable the gic cpu interface */ 112*b4315306SDan Handley arm_gic_cpuif_setup(); 113*b4315306SDan Handley 114*b4315306SDan Handley /* todo: Is this setup only needed after a cold boot? */ 115*b4315306SDan Handley arm_gic_pcpu_distif_setup(); 116*b4315306SDan Handley 117*b4315306SDan Handley /* Clear the mailbox for this cpu. */ 118*b4315306SDan Handley css_program_mailbox(mpidr, 0); 119*b4315306SDan Handley } 120*b4315306SDan Handley 121*b4315306SDan Handley /******************************************************************************* 122*b4315306SDan Handley * Common function called while turning a cpu off or suspending it. It is called 123*b4315306SDan Handley * from css_off() or css_suspend() when these functions in turn are called for 124*b4315306SDan Handley * the highest affinity level which will be powered down. It performs the 125*b4315306SDan Handley * actions common to the OFF and SUSPEND calls. 126*b4315306SDan Handley ******************************************************************************/ 127*b4315306SDan Handley static void css_power_down_common(uint32_t afflvl) 128*b4315306SDan Handley { 129*b4315306SDan Handley uint32_t cluster_state = scpi_power_on; 130*b4315306SDan Handley 131*b4315306SDan Handley /* Prevent interrupts from spuriously waking up this cpu */ 132*b4315306SDan Handley arm_gic_cpuif_deactivate(); 133*b4315306SDan Handley 134*b4315306SDan Handley /* Cluster is to be turned off, so disable coherency */ 135*b4315306SDan Handley if (afflvl > MPIDR_AFFLVL0) { 136*b4315306SDan Handley cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); 137*b4315306SDan Handley cluster_state = scpi_power_off; 138*b4315306SDan Handley } 139*b4315306SDan Handley 140*b4315306SDan Handley /* 141*b4315306SDan Handley * Ask the SCP to power down the appropriate components depending upon 142*b4315306SDan Handley * their state. 143*b4315306SDan Handley */ 144*b4315306SDan Handley scpi_set_css_power_state(read_mpidr_el1(), 145*b4315306SDan Handley scpi_power_off, 146*b4315306SDan Handley cluster_state, 147*b4315306SDan Handley scpi_power_on); 148*b4315306SDan Handley } 149*b4315306SDan Handley 150*b4315306SDan Handley /******************************************************************************* 151*b4315306SDan Handley * Handler called when an affinity instance is about to be turned off. The 152*b4315306SDan Handley * level and mpidr determine the affinity instance. The 'state' arg. allows the 153*b4315306SDan Handley * platform to decide whether the cluster is being turned off and take 154*b4315306SDan Handley * appropriate actions. 155*b4315306SDan Handley * 156*b4315306SDan Handley * CAUTION: There is no guarantee that caches will remain turned on across calls 157*b4315306SDan Handley * to this function as each affinity level is dealt with. So do not write & read 158*b4315306SDan Handley * global variables across calls. It will be wise to do flush a write to the 159*b4315306SDan Handley * global to prevent unpredictable results. 160*b4315306SDan Handley ******************************************************************************/ 161*b4315306SDan Handley static void css_affinst_off(uint32_t afflvl, uint32_t state) 162*b4315306SDan Handley { 163*b4315306SDan Handley /* Determine if any platform actions need to be executed */ 164*b4315306SDan Handley if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) 165*b4315306SDan Handley return; 166*b4315306SDan Handley 167*b4315306SDan Handley css_power_down_common(afflvl); 168*b4315306SDan Handley } 169*b4315306SDan Handley 170*b4315306SDan Handley /******************************************************************************* 171*b4315306SDan Handley * Handler called when an affinity instance is about to be suspended. The 172*b4315306SDan Handley * level and mpidr determine the affinity instance. The 'state' arg. allows the 173*b4315306SDan Handley * platform to decide whether the cluster is being turned off and take apt 174*b4315306SDan Handley * actions. The 'sec_entrypoint' determines the address in BL3-1 from where 175*b4315306SDan Handley * execution should resume. 176*b4315306SDan Handley * 177*b4315306SDan Handley * CAUTION: There is no guarantee that caches will remain turned on across calls 178*b4315306SDan Handley * to this function as each affinity level is dealt with. So do not write & read 179*b4315306SDan Handley * global variables across calls. It will be wise to do flush a write to the 180*b4315306SDan Handley * global to prevent unpredictable results. 181*b4315306SDan Handley ******************************************************************************/ 182*b4315306SDan Handley static void css_affinst_suspend(uint64_t sec_entrypoint, 183*b4315306SDan Handley uint32_t afflvl, 184*b4315306SDan Handley uint32_t state) 185*b4315306SDan Handley { 186*b4315306SDan Handley /* Determine if any platform actions need to be executed */ 187*b4315306SDan Handley if (arm_do_affinst_actions(afflvl, state) == -EAGAIN) 188*b4315306SDan Handley return; 189*b4315306SDan Handley 190*b4315306SDan Handley /* 191*b4315306SDan Handley * Setup mailbox with address for CPU entrypoint when it next powers up. 192*b4315306SDan Handley */ 193*b4315306SDan Handley css_program_mailbox(read_mpidr_el1(), sec_entrypoint); 194*b4315306SDan Handley 195*b4315306SDan Handley css_power_down_common(afflvl); 196*b4315306SDan Handley } 197*b4315306SDan Handley 198*b4315306SDan Handley /******************************************************************************* 199*b4315306SDan Handley * Handler called when an affinity instance has just been powered on after 200*b4315306SDan Handley * having been suspended earlier. The level and mpidr determine the affinity 201*b4315306SDan Handley * instance. 202*b4315306SDan Handley * TODO: At the moment we reuse the on finisher and reinitialize the secure 203*b4315306SDan Handley * context. Need to implement a separate suspend finisher. 204*b4315306SDan Handley ******************************************************************************/ 205*b4315306SDan Handley static void css_affinst_suspend_finish(uint32_t afflvl, 206*b4315306SDan Handley uint32_t state) 207*b4315306SDan Handley { 208*b4315306SDan Handley css_affinst_on_finish(afflvl, state); 209*b4315306SDan Handley } 210*b4315306SDan Handley 211*b4315306SDan Handley /******************************************************************************* 212*b4315306SDan Handley * Handlers to shutdown/reboot the system 213*b4315306SDan Handley ******************************************************************************/ 214*b4315306SDan Handley static void __dead2 css_system_off(void) 215*b4315306SDan Handley { 216*b4315306SDan Handley uint32_t response; 217*b4315306SDan Handley 218*b4315306SDan Handley /* Send the power down request to the SCP */ 219*b4315306SDan Handley response = scpi_sys_power_state(scpi_system_shutdown); 220*b4315306SDan Handley 221*b4315306SDan Handley if (response != SCP_OK) { 222*b4315306SDan Handley ERROR("CSS System Off: SCP error %u.\n", response); 223*b4315306SDan Handley panic(); 224*b4315306SDan Handley } 225*b4315306SDan Handley wfi(); 226*b4315306SDan Handley ERROR("CSS System Off: operation not handled.\n"); 227*b4315306SDan Handley panic(); 228*b4315306SDan Handley } 229*b4315306SDan Handley 230*b4315306SDan Handley static void __dead2 css_system_reset(void) 231*b4315306SDan Handley { 232*b4315306SDan Handley uint32_t response; 233*b4315306SDan Handley 234*b4315306SDan Handley /* Send the system reset request to the SCP */ 235*b4315306SDan Handley response = scpi_sys_power_state(scpi_system_reboot); 236*b4315306SDan Handley 237*b4315306SDan Handley if (response != SCP_OK) { 238*b4315306SDan Handley ERROR("CSS System Reset: SCP error %u.\n", response); 239*b4315306SDan Handley panic(); 240*b4315306SDan Handley } 241*b4315306SDan Handley wfi(); 242*b4315306SDan Handley ERROR("CSS System Reset: operation not handled.\n"); 243*b4315306SDan Handley panic(); 244*b4315306SDan Handley } 245*b4315306SDan Handley 246*b4315306SDan Handley /******************************************************************************* 247*b4315306SDan Handley * Handler called when an affinity instance is about to enter standby. 248*b4315306SDan Handley ******************************************************************************/ 249*b4315306SDan Handley void css_affinst_standby(unsigned int power_state) 250*b4315306SDan Handley { 251*b4315306SDan Handley unsigned int scr; 252*b4315306SDan Handley 253*b4315306SDan Handley scr = read_scr_el3(); 254*b4315306SDan Handley /* Enable PhysicalIRQ bit for NS world to wake the CPU */ 255*b4315306SDan Handley write_scr_el3(scr | SCR_IRQ_BIT); 256*b4315306SDan Handley isb(); 257*b4315306SDan Handley dsb(); 258*b4315306SDan Handley wfi(); 259*b4315306SDan Handley 260*b4315306SDan Handley /* 261*b4315306SDan Handley * Restore SCR to the original value, synchronisation of scr_el3 is 262*b4315306SDan Handley * done by eret while el3_exit to save some execution cycles. 263*b4315306SDan Handley */ 264*b4315306SDan Handley write_scr_el3(scr); 265*b4315306SDan Handley } 266*b4315306SDan Handley 267*b4315306SDan Handley /******************************************************************************* 268*b4315306SDan Handley * Export the platform handlers to enable psci to invoke them 269*b4315306SDan Handley ******************************************************************************/ 270*b4315306SDan Handley static const plat_pm_ops_t css_ops = { 271*b4315306SDan Handley .affinst_on = css_affinst_on, 272*b4315306SDan Handley .affinst_on_finish = css_affinst_on_finish, 273*b4315306SDan Handley .affinst_off = css_affinst_off, 274*b4315306SDan Handley .affinst_standby = css_affinst_standby, 275*b4315306SDan Handley .affinst_suspend = css_affinst_suspend, 276*b4315306SDan Handley .affinst_suspend_finish = css_affinst_suspend_finish, 277*b4315306SDan Handley .system_off = css_system_off, 278*b4315306SDan Handley .system_reset = css_system_reset, 279*b4315306SDan Handley .validate_power_state = arm_validate_power_state 280*b4315306SDan Handley }; 281*b4315306SDan Handley 282*b4315306SDan Handley /******************************************************************************* 283*b4315306SDan Handley * Export the platform specific power ops. 284*b4315306SDan Handley ******************************************************************************/ 285*b4315306SDan Handley int32_t platform_setup_pm(const plat_pm_ops_t **plat_ops) 286*b4315306SDan Handley { 287*b4315306SDan Handley *plat_ops = &css_ops; 288*b4315306SDan Handley return 0; 289*b4315306SDan Handley } 290