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