1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2013-2023, 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 <common/bl_common.h> 11*91f16700Schasinglulu #include <common/debug.h> 12*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h> 13*91f16700Schasinglulu #include <plat/common/platform.h> 14*91f16700Schasinglulu 15*91f16700Schasinglulu #include "opteed_private.h" 16*91f16700Schasinglulu 17*91f16700Schasinglulu /******************************************************************************* 18*91f16700Schasinglulu * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any 19*91f16700Schasinglulu * actions needed. Nothing at the moment. 20*91f16700Schasinglulu ******************************************************************************/ 21*91f16700Schasinglulu static void opteed_cpu_on_handler(u_register_t target_cpu) 22*91f16700Schasinglulu { 23*91f16700Schasinglulu } 24*91f16700Schasinglulu 25*91f16700Schasinglulu /******************************************************************************* 26*91f16700Schasinglulu * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions 27*91f16700Schasinglulu * needed 28*91f16700Schasinglulu ******************************************************************************/ 29*91f16700Schasinglulu static int32_t opteed_cpu_off_handler(u_register_t unused) 30*91f16700Schasinglulu { 31*91f16700Schasinglulu int32_t rc = 0; 32*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 33*91f16700Schasinglulu optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 34*91f16700Schasinglulu 35*91f16700Schasinglulu if (get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_UNKNOWN) { 36*91f16700Schasinglulu return 0; 37*91f16700Schasinglulu } 38*91f16700Schasinglulu 39*91f16700Schasinglulu assert(optee_vector_table); 40*91f16700Schasinglulu assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 41*91f16700Schasinglulu 42*91f16700Schasinglulu /* Program the entry point and enter OPTEE */ 43*91f16700Schasinglulu cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_off_entry); 44*91f16700Schasinglulu rc = opteed_synchronous_sp_entry(optee_ctx); 45*91f16700Schasinglulu 46*91f16700Schasinglulu /* 47*91f16700Schasinglulu * Read the response from OPTEE. A non-zero return means that 48*91f16700Schasinglulu * something went wrong while communicating with OPTEE. 49*91f16700Schasinglulu */ 50*91f16700Schasinglulu if (rc != 0) 51*91f16700Schasinglulu panic(); 52*91f16700Schasinglulu 53*91f16700Schasinglulu /* 54*91f16700Schasinglulu * Reset OPTEE's context for a fresh start when this cpu is turned on 55*91f16700Schasinglulu * subsequently. 56*91f16700Schasinglulu */ 57*91f16700Schasinglulu set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF); 58*91f16700Schasinglulu 59*91f16700Schasinglulu return 0; 60*91f16700Schasinglulu } 61*91f16700Schasinglulu 62*91f16700Schasinglulu /******************************************************************************* 63*91f16700Schasinglulu * This cpu is being suspended. S-EL1 state must have been saved in the 64*91f16700Schasinglulu * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 65*91f16700Schasinglulu ******************************************************************************/ 66*91f16700Schasinglulu static void opteed_cpu_suspend_handler(u_register_t max_off_pwrlvl) 67*91f16700Schasinglulu { 68*91f16700Schasinglulu int32_t rc = 0; 69*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 70*91f16700Schasinglulu optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 71*91f16700Schasinglulu 72*91f16700Schasinglulu if (get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_UNKNOWN) { 73*91f16700Schasinglulu return; 74*91f16700Schasinglulu } 75*91f16700Schasinglulu 76*91f16700Schasinglulu assert(optee_vector_table); 77*91f16700Schasinglulu assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 78*91f16700Schasinglulu 79*91f16700Schasinglulu write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0, 80*91f16700Schasinglulu max_off_pwrlvl); 81*91f16700Schasinglulu 82*91f16700Schasinglulu /* Program the entry point and enter OPTEE */ 83*91f16700Schasinglulu cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_suspend_entry); 84*91f16700Schasinglulu rc = opteed_synchronous_sp_entry(optee_ctx); 85*91f16700Schasinglulu 86*91f16700Schasinglulu /* 87*91f16700Schasinglulu * Read the response from OPTEE. A non-zero return means that 88*91f16700Schasinglulu * something went wrong while communicating with OPTEE. 89*91f16700Schasinglulu */ 90*91f16700Schasinglulu if (rc != 0) 91*91f16700Schasinglulu panic(); 92*91f16700Schasinglulu 93*91f16700Schasinglulu /* Update its context to reflect the state OPTEE is in */ 94*91f16700Schasinglulu set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND); 95*91f16700Schasinglulu } 96*91f16700Schasinglulu 97*91f16700Schasinglulu /******************************************************************************* 98*91f16700Schasinglulu * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits 99*91f16700Schasinglulu * before passing control back to the Secure Monitor. Entry in S-El1 is done 100*91f16700Schasinglulu * after initialising minimal architectural state that guarantees safe 101*91f16700Schasinglulu * execution. 102*91f16700Schasinglulu ******************************************************************************/ 103*91f16700Schasinglulu void opteed_cpu_on_finish_handler(u_register_t unused) 104*91f16700Schasinglulu { 105*91f16700Schasinglulu int32_t rc = 0; 106*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 107*91f16700Schasinglulu optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 108*91f16700Schasinglulu entry_point_info_t optee_on_entrypoint; 109*91f16700Schasinglulu 110*91f16700Schasinglulu assert(optee_vector_table); 111*91f16700Schasinglulu assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF || 112*91f16700Schasinglulu get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_UNKNOWN); 113*91f16700Schasinglulu 114*91f16700Schasinglulu opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw, 115*91f16700Schasinglulu (uint64_t)&optee_vector_table->cpu_on_entry, 116*91f16700Schasinglulu 0, 0, 0, optee_ctx); 117*91f16700Schasinglulu 118*91f16700Schasinglulu /* Initialise this cpu's secure context */ 119*91f16700Schasinglulu cm_init_my_context(&optee_on_entrypoint); 120*91f16700Schasinglulu 121*91f16700Schasinglulu /* Enter OPTEE */ 122*91f16700Schasinglulu rc = opteed_synchronous_sp_entry(optee_ctx); 123*91f16700Schasinglulu 124*91f16700Schasinglulu /* 125*91f16700Schasinglulu * Read the response from OPTEE. A non-zero return means that 126*91f16700Schasinglulu * something went wrong while communicating with OPTEE. 127*91f16700Schasinglulu */ 128*91f16700Schasinglulu if (rc != 0) 129*91f16700Schasinglulu panic(); 130*91f16700Schasinglulu 131*91f16700Schasinglulu /* Update its context to reflect the state OPTEE is in */ 132*91f16700Schasinglulu set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 133*91f16700Schasinglulu } 134*91f16700Schasinglulu 135*91f16700Schasinglulu /******************************************************************************* 136*91f16700Schasinglulu * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it 137*91f16700Schasinglulu * completed the preceding suspend call. Use that context to program an entry 138*91f16700Schasinglulu * into OPTEE to allow it to do any remaining book keeping 139*91f16700Schasinglulu ******************************************************************************/ 140*91f16700Schasinglulu static void opteed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl) 141*91f16700Schasinglulu { 142*91f16700Schasinglulu int32_t rc = 0; 143*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 144*91f16700Schasinglulu optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 145*91f16700Schasinglulu 146*91f16700Schasinglulu if (get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_UNKNOWN) { 147*91f16700Schasinglulu return; 148*91f16700Schasinglulu } 149*91f16700Schasinglulu 150*91f16700Schasinglulu assert(optee_vector_table); 151*91f16700Schasinglulu assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND); 152*91f16700Schasinglulu 153*91f16700Schasinglulu /* Program the entry point, max_off_pwrlvl and enter the SP */ 154*91f16700Schasinglulu write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), 155*91f16700Schasinglulu CTX_GPREG_X0, 156*91f16700Schasinglulu max_off_pwrlvl); 157*91f16700Schasinglulu cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_resume_entry); 158*91f16700Schasinglulu rc = opteed_synchronous_sp_entry(optee_ctx); 159*91f16700Schasinglulu 160*91f16700Schasinglulu /* 161*91f16700Schasinglulu * Read the response from OPTEE. A non-zero return means that 162*91f16700Schasinglulu * something went wrong while communicating with OPTEE. 163*91f16700Schasinglulu */ 164*91f16700Schasinglulu if (rc != 0) 165*91f16700Schasinglulu panic(); 166*91f16700Schasinglulu 167*91f16700Schasinglulu /* Update its context to reflect the state OPTEE is in */ 168*91f16700Schasinglulu set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 169*91f16700Schasinglulu } 170*91f16700Schasinglulu 171*91f16700Schasinglulu /******************************************************************************* 172*91f16700Schasinglulu * Return the type of OPTEE the OPTEED is dealing with. Report the current 173*91f16700Schasinglulu * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 174*91f16700Schasinglulu ******************************************************************************/ 175*91f16700Schasinglulu static int32_t opteed_cpu_migrate_info(u_register_t *resident_cpu) 176*91f16700Schasinglulu { 177*91f16700Schasinglulu return OPTEE_MIGRATE_INFO; 178*91f16700Schasinglulu } 179*91f16700Schasinglulu 180*91f16700Schasinglulu /******************************************************************************* 181*91f16700Schasinglulu * System is about to be switched off. Allow the OPTEED/OPTEE to perform 182*91f16700Schasinglulu * any actions needed. 183*91f16700Schasinglulu ******************************************************************************/ 184*91f16700Schasinglulu static void opteed_system_off(void) 185*91f16700Schasinglulu { 186*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 187*91f16700Schasinglulu optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 188*91f16700Schasinglulu 189*91f16700Schasinglulu /* 190*91f16700Schasinglulu * OP-TEE must have been initialized in order to reach this location so 191*91f16700Schasinglulu * it is safe to init the CPU context if not already done for this core. 192*91f16700Schasinglulu */ 193*91f16700Schasinglulu if (get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_UNKNOWN) { 194*91f16700Schasinglulu opteed_cpu_on_finish_handler(0); 195*91f16700Schasinglulu } 196*91f16700Schasinglulu 197*91f16700Schasinglulu assert(optee_vector_table); 198*91f16700Schasinglulu assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 199*91f16700Schasinglulu 200*91f16700Schasinglulu /* Program the entry point */ 201*91f16700Schasinglulu cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_off_entry); 202*91f16700Schasinglulu 203*91f16700Schasinglulu /* Enter OPTEE. We do not care about the return value because we 204*91f16700Schasinglulu * must continue the shutdown anyway */ 205*91f16700Schasinglulu opteed_synchronous_sp_entry(optee_ctx); 206*91f16700Schasinglulu } 207*91f16700Schasinglulu 208*91f16700Schasinglulu /******************************************************************************* 209*91f16700Schasinglulu * System is about to be reset. Allow the OPTEED/OPTEE to perform 210*91f16700Schasinglulu * any actions needed. 211*91f16700Schasinglulu ******************************************************************************/ 212*91f16700Schasinglulu static void opteed_system_reset(void) 213*91f16700Schasinglulu { 214*91f16700Schasinglulu uint32_t linear_id = plat_my_core_pos(); 215*91f16700Schasinglulu optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 216*91f16700Schasinglulu 217*91f16700Schasinglulu /* 218*91f16700Schasinglulu * OP-TEE must have been initialized in order to reach this location so 219*91f16700Schasinglulu * it is safe to init the CPU context if not already done for this core. 220*91f16700Schasinglulu */ 221*91f16700Schasinglulu if (get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_UNKNOWN) { 222*91f16700Schasinglulu opteed_cpu_on_finish_handler(0); 223*91f16700Schasinglulu } 224*91f16700Schasinglulu 225*91f16700Schasinglulu assert(optee_vector_table); 226*91f16700Schasinglulu assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 227*91f16700Schasinglulu 228*91f16700Schasinglulu /* Program the entry point */ 229*91f16700Schasinglulu cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_reset_entry); 230*91f16700Schasinglulu 231*91f16700Schasinglulu /* Enter OPTEE. We do not care about the return value because we 232*91f16700Schasinglulu * must continue the reset anyway */ 233*91f16700Schasinglulu opteed_synchronous_sp_entry(optee_ctx); 234*91f16700Schasinglulu } 235*91f16700Schasinglulu 236*91f16700Schasinglulu 237*91f16700Schasinglulu /******************************************************************************* 238*91f16700Schasinglulu * Structure populated by the OPTEE Dispatcher to be given a chance to 239*91f16700Schasinglulu * perform any OPTEE bookkeeping before PSCI executes a power mgmt. 240*91f16700Schasinglulu * operation. 241*91f16700Schasinglulu ******************************************************************************/ 242*91f16700Schasinglulu const spd_pm_ops_t opteed_pm = { 243*91f16700Schasinglulu .svc_on = opteed_cpu_on_handler, 244*91f16700Schasinglulu .svc_off = opteed_cpu_off_handler, 245*91f16700Schasinglulu .svc_suspend = opteed_cpu_suspend_handler, 246*91f16700Schasinglulu .svc_on_finish = opteed_cpu_on_finish_handler, 247*91f16700Schasinglulu .svc_suspend_finish = opteed_cpu_suspend_finish_handler, 248*91f16700Schasinglulu .svc_migrate = NULL, 249*91f16700Schasinglulu .svc_migrate_info = opteed_cpu_migrate_info, 250*91f16700Schasinglulu .svc_system_off = opteed_system_off, 251*91f16700Schasinglulu .svc_system_reset = opteed_system_reset, 252*91f16700Schasinglulu }; 253