1*607084eeSAchin Gupta /* 2*607084eeSAchin Gupta * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. 3*607084eeSAchin Gupta * 4*607084eeSAchin Gupta * Redistribution and use in source and binary forms, with or without 5*607084eeSAchin Gupta * modification, are permitted provided that the following conditions are met: 6*607084eeSAchin Gupta * 7*607084eeSAchin Gupta * Redistributions of source code must retain the above copyright notice, this 8*607084eeSAchin Gupta * list of conditions and the following disclaimer. 9*607084eeSAchin Gupta * 10*607084eeSAchin Gupta * Redistributions in binary form must reproduce the above copyright notice, 11*607084eeSAchin Gupta * this list of conditions and the following disclaimer in the documentation 12*607084eeSAchin Gupta * and/or other materials provided with the distribution. 13*607084eeSAchin Gupta * 14*607084eeSAchin Gupta * Neither the name of ARM nor the names of its contributors may be used 15*607084eeSAchin Gupta * to endorse or promote products derived from this software without specific 16*607084eeSAchin Gupta * prior written permission. 17*607084eeSAchin Gupta * 18*607084eeSAchin Gupta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*607084eeSAchin Gupta * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*607084eeSAchin Gupta * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*607084eeSAchin Gupta * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*607084eeSAchin Gupta * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*607084eeSAchin Gupta * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*607084eeSAchin Gupta * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*607084eeSAchin Gupta * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*607084eeSAchin Gupta * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*607084eeSAchin Gupta * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*607084eeSAchin Gupta * POSSIBILITY OF SUCH DAMAGE. 29*607084eeSAchin Gupta */ 30*607084eeSAchin Gupta 31*607084eeSAchin Gupta #include <stdio.h> 32*607084eeSAchin Gupta #include <string.h> 33*607084eeSAchin Gupta #include <assert.h> 34*607084eeSAchin Gupta #include <arch_helpers.h> 35*607084eeSAchin Gupta #include <console.h> 36*607084eeSAchin Gupta #include <platform.h> 37*607084eeSAchin Gupta #include <psci_private.h> 38*607084eeSAchin Gupta #include <context_mgmt.h> 39*607084eeSAchin Gupta #include <runtime_svc.h> 40*607084eeSAchin Gupta #include <bl31.h> 41*607084eeSAchin Gupta #include <bl32.h> 42*607084eeSAchin Gupta #include <psci.h> 43*607084eeSAchin Gupta #include <tspd_private.h> 44*607084eeSAchin Gupta #include <debug.h> 45*607084eeSAchin Gupta 46*607084eeSAchin Gupta /******************************************************************************* 47*607084eeSAchin Gupta * The target cpu is being turned on. Allow the TSPD/TSP to perform any actions 48*607084eeSAchin Gupta * needed. Nothing at the moment. 49*607084eeSAchin Gupta ******************************************************************************/ 50*607084eeSAchin Gupta static void tspd_cpu_on_handler(uint64_t target_cpu) 51*607084eeSAchin Gupta { 52*607084eeSAchin Gupta } 53*607084eeSAchin Gupta 54*607084eeSAchin Gupta /******************************************************************************* 55*607084eeSAchin Gupta * This cpu is being turned off. Allow the TSPD/TSP to perform any actions 56*607084eeSAchin Gupta * needed 57*607084eeSAchin Gupta ******************************************************************************/ 58*607084eeSAchin Gupta static int32_t tspd_cpu_off_handler(uint64_t cookie) 59*607084eeSAchin Gupta { 60*607084eeSAchin Gupta int32_t rc = 0; 61*607084eeSAchin Gupta uint64_t mpidr = read_mpidr(); 62*607084eeSAchin Gupta uint32_t linear_id = platform_get_core_pos(mpidr); 63*607084eeSAchin Gupta tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; 64*607084eeSAchin Gupta 65*607084eeSAchin Gupta assert(tsp_entry_info); 66*607084eeSAchin Gupta assert(tsp_ctx->state == TSP_STATE_ON); 67*607084eeSAchin Gupta 68*607084eeSAchin Gupta /* Program the entry point and enter the TSP */ 69*607084eeSAchin Gupta cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_off_entry); 70*607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 71*607084eeSAchin Gupta 72*607084eeSAchin Gupta /* 73*607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 74*607084eeSAchin Gupta * something went wrong while communicating with the TSP. 75*607084eeSAchin Gupta */ 76*607084eeSAchin Gupta if (rc != 0) 77*607084eeSAchin Gupta panic(); 78*607084eeSAchin Gupta 79*607084eeSAchin Gupta /* 80*607084eeSAchin Gupta * Reset TSP's context for a fresh start when this cpu is turned on 81*607084eeSAchin Gupta * subsequently. 82*607084eeSAchin Gupta */ 83*607084eeSAchin Gupta tsp_ctx->state = TSP_STATE_OFF; 84*607084eeSAchin Gupta 85*607084eeSAchin Gupta return 0; 86*607084eeSAchin Gupta } 87*607084eeSAchin Gupta 88*607084eeSAchin Gupta /******************************************************************************* 89*607084eeSAchin Gupta * This cpu is being suspended. S-EL1 state must have been saved in the 90*607084eeSAchin Gupta * resident cpu (mpidr format) if it is a UP/UP migratable TSP. 91*607084eeSAchin Gupta ******************************************************************************/ 92*607084eeSAchin Gupta static void tspd_cpu_suspend_handler(uint64_t power_state) 93*607084eeSAchin Gupta { 94*607084eeSAchin Gupta int32_t rc = 0; 95*607084eeSAchin Gupta uint64_t mpidr = read_mpidr(); 96*607084eeSAchin Gupta uint32_t linear_id = platform_get_core_pos(mpidr); 97*607084eeSAchin Gupta tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; 98*607084eeSAchin Gupta 99*607084eeSAchin Gupta assert(tsp_entry_info); 100*607084eeSAchin Gupta assert(tsp_ctx->state == TSP_STATE_ON); 101*607084eeSAchin Gupta 102*607084eeSAchin Gupta /* Program the entry point, power_state parameter and enter the TSP */ 103*607084eeSAchin Gupta write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), 104*607084eeSAchin Gupta CTX_GPREG_X0, 105*607084eeSAchin Gupta power_state); 106*607084eeSAchin Gupta cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_suspend_entry); 107*607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 108*607084eeSAchin Gupta 109*607084eeSAchin Gupta /* 110*607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 111*607084eeSAchin Gupta * something went wrong while communicating with the TSP. 112*607084eeSAchin Gupta */ 113*607084eeSAchin Gupta if (rc != 0) 114*607084eeSAchin Gupta panic(); 115*607084eeSAchin Gupta 116*607084eeSAchin Gupta /* Update its context to reflect the state the TSP is in */ 117*607084eeSAchin Gupta tsp_ctx->state = TSP_STATE_SUSPEND; 118*607084eeSAchin Gupta } 119*607084eeSAchin Gupta 120*607084eeSAchin Gupta /******************************************************************************* 121*607084eeSAchin Gupta * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits 122*607084eeSAchin Gupta * before passing control back to the Secure Monitor. Entry in S-El1 is done 123*607084eeSAchin Gupta * after initialising minimal architectural state that guarantees safe 124*607084eeSAchin Gupta * execution. 125*607084eeSAchin Gupta ******************************************************************************/ 126*607084eeSAchin Gupta static void tspd_cpu_on_finish_handler(uint64_t cookie) 127*607084eeSAchin Gupta { 128*607084eeSAchin Gupta int32_t rc = 0; 129*607084eeSAchin Gupta uint64_t mpidr = read_mpidr(); 130*607084eeSAchin Gupta uint32_t linear_id = platform_get_core_pos(mpidr); 131*607084eeSAchin Gupta tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; 132*607084eeSAchin Gupta 133*607084eeSAchin Gupta assert(tsp_entry_info); 134*607084eeSAchin Gupta assert(tsp_ctx->state == TSP_STATE_OFF); 135*607084eeSAchin Gupta 136*607084eeSAchin Gupta /* Initialise this cpu's secure context */ 137*607084eeSAchin Gupta tspd_init_secure_context((uint64_t) tsp_entry_info->cpu_on_entry, 138*607084eeSAchin Gupta TSP_AARCH64, 139*607084eeSAchin Gupta mpidr, 140*607084eeSAchin Gupta tsp_ctx); 141*607084eeSAchin Gupta 142*607084eeSAchin Gupta /* Enter the TSP */ 143*607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 144*607084eeSAchin Gupta 145*607084eeSAchin Gupta /* 146*607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 147*607084eeSAchin Gupta * something went wrong while communicating with the SP. 148*607084eeSAchin Gupta */ 149*607084eeSAchin Gupta if (rc != 0) 150*607084eeSAchin Gupta panic(); 151*607084eeSAchin Gupta 152*607084eeSAchin Gupta /* Update its context to reflect the state the SP is in */ 153*607084eeSAchin Gupta tsp_ctx->state = TSP_STATE_ON; 154*607084eeSAchin Gupta } 155*607084eeSAchin Gupta 156*607084eeSAchin Gupta /******************************************************************************* 157*607084eeSAchin Gupta * This cpu has resumed from suspend. The SPD saved the TSP context when it 158*607084eeSAchin Gupta * completed the preceding suspend call. Use that context to program an entry 159*607084eeSAchin Gupta * into the TSP to allow it to do any remaining book keeping 160*607084eeSAchin Gupta ******************************************************************************/ 161*607084eeSAchin Gupta static void tspd_cpu_suspend_finish_handler(uint64_t suspend_level) 162*607084eeSAchin Gupta { 163*607084eeSAchin Gupta int32_t rc = 0; 164*607084eeSAchin Gupta uint64_t mpidr = read_mpidr(); 165*607084eeSAchin Gupta uint32_t linear_id = platform_get_core_pos(mpidr); 166*607084eeSAchin Gupta tsp_context *tsp_ctx = &tspd_sp_context[linear_id]; 167*607084eeSAchin Gupta 168*607084eeSAchin Gupta assert(tsp_entry_info); 169*607084eeSAchin Gupta assert(tsp_ctx->state == TSP_STATE_SUSPEND); 170*607084eeSAchin Gupta 171*607084eeSAchin Gupta /* Program the entry point, suspend_level and enter the SP */ 172*607084eeSAchin Gupta write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), 173*607084eeSAchin Gupta CTX_GPREG_X0, 174*607084eeSAchin Gupta suspend_level); 175*607084eeSAchin Gupta cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_resume_entry); 176*607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 177*607084eeSAchin Gupta 178*607084eeSAchin Gupta /* 179*607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 180*607084eeSAchin Gupta * something went wrong while communicating with the TSP. 181*607084eeSAchin Gupta */ 182*607084eeSAchin Gupta if (rc != 0) 183*607084eeSAchin Gupta panic(); 184*607084eeSAchin Gupta 185*607084eeSAchin Gupta /* Update its context to reflect the state the SP is in */ 186*607084eeSAchin Gupta tsp_ctx->state = TSP_STATE_ON; 187*607084eeSAchin Gupta } 188*607084eeSAchin Gupta 189*607084eeSAchin Gupta /******************************************************************************* 190*607084eeSAchin Gupta * Return the type of TSP the TSPD is dealing with. Report the current resident 191*607084eeSAchin Gupta * cpu (mpidr format) if it is a UP/UP migratable TSP. 192*607084eeSAchin Gupta ******************************************************************************/ 193*607084eeSAchin Gupta static int32_t tspd_cpu_migrate_info(uint64_t *resident_cpu) 194*607084eeSAchin Gupta { 195*607084eeSAchin Gupta return TSP_MIGRATE_INFO; 196*607084eeSAchin Gupta } 197*607084eeSAchin Gupta 198*607084eeSAchin Gupta /******************************************************************************* 199*607084eeSAchin Gupta * Structure populated by the TSP Dispatcher to be given a chance to perform any 200*607084eeSAchin Gupta * TSP bookkeeping before PSCI executes a power mgmt. operation. 201*607084eeSAchin Gupta ******************************************************************************/ 202*607084eeSAchin Gupta const spd_pm_ops spd_pm = { 203*607084eeSAchin Gupta tspd_cpu_on_handler, 204*607084eeSAchin Gupta tspd_cpu_off_handler, 205*607084eeSAchin Gupta tspd_cpu_suspend_handler, 206*607084eeSAchin Gupta tspd_cpu_on_finish_handler, 207*607084eeSAchin Gupta tspd_cpu_suspend_finish_handler, 208*607084eeSAchin Gupta NULL, 209*607084eeSAchin Gupta tspd_cpu_migrate_info 210*607084eeSAchin Gupta }; 211*607084eeSAchin Gupta 212