1aa5da461SJens Wiklander /* 2d59a6accSEdison Ai * Copyright (c) 2013-2017, 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> 8*09d40e0eSAntonio Nino Diaz 9*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 10*09d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 11*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 12*09d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/context_mgmt.h> 13*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 14*09d40e0eSAntonio 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 35776ff52aSDaniel Boulby assert(optee_vector_table); 36aa5da461SJens Wiklander assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 37aa5da461SJens Wiklander 38aa5da461SJens Wiklander /* Program the entry point and enter OPTEE */ 39776ff52aSDaniel Boulby cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_off_entry); 40aa5da461SJens Wiklander rc = opteed_synchronous_sp_entry(optee_ctx); 41aa5da461SJens Wiklander 42aa5da461SJens Wiklander /* 43aa5da461SJens Wiklander * Read the response from OPTEE. A non-zero return means that 44aa5da461SJens Wiklander * something went wrong while communicating with OPTEE. 45aa5da461SJens Wiklander */ 46aa5da461SJens Wiklander if (rc != 0) 47aa5da461SJens Wiklander panic(); 48aa5da461SJens Wiklander 49aa5da461SJens Wiklander /* 50aa5da461SJens Wiklander * Reset OPTEE's context for a fresh start when this cpu is turned on 51aa5da461SJens Wiklander * subsequently. 52aa5da461SJens Wiklander */ 53aa5da461SJens Wiklander set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF); 54aa5da461SJens Wiklander 55aa5da461SJens Wiklander return 0; 56aa5da461SJens Wiklander } 57aa5da461SJens Wiklander 58aa5da461SJens Wiklander /******************************************************************************* 59aa5da461SJens Wiklander * This cpu is being suspended. S-EL1 state must have been saved in the 60aa5da461SJens Wiklander * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 61aa5da461SJens Wiklander ******************************************************************************/ 6257d1e5faSMasahiro Yamada static void opteed_cpu_suspend_handler(u_register_t max_off_pwrlvl) 63aa5da461SJens Wiklander { 64aa5da461SJens Wiklander int32_t rc = 0; 65fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 66aa5da461SJens Wiklander optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 67aa5da461SJens Wiklander 68776ff52aSDaniel Boulby assert(optee_vector_table); 69aa5da461SJens Wiklander assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 70aa5da461SJens Wiklander 71820540bfSJorge Ramirez-Ortiz write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0, 72820540bfSJorge Ramirez-Ortiz max_off_pwrlvl); 73820540bfSJorge Ramirez-Ortiz 7431244d74SSoby Mathew /* Program the entry point and enter OPTEE */ 75776ff52aSDaniel Boulby cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_suspend_entry); 76aa5da461SJens Wiklander rc = opteed_synchronous_sp_entry(optee_ctx); 77aa5da461SJens Wiklander 78aa5da461SJens Wiklander /* 79aa5da461SJens Wiklander * Read the response from OPTEE. A non-zero return means that 80aa5da461SJens Wiklander * something went wrong while communicating with OPTEE. 81aa5da461SJens Wiklander */ 82aa5da461SJens Wiklander if (rc != 0) 83aa5da461SJens Wiklander panic(); 84aa5da461SJens Wiklander 85aa5da461SJens Wiklander /* Update its context to reflect the state OPTEE is in */ 86aa5da461SJens Wiklander set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND); 87aa5da461SJens Wiklander } 88aa5da461SJens Wiklander 89aa5da461SJens Wiklander /******************************************************************************* 90aa5da461SJens Wiklander * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits 91aa5da461SJens Wiklander * before passing control back to the Secure Monitor. Entry in S-El1 is done 92aa5da461SJens Wiklander * after initialising minimal architectural state that guarantees safe 93aa5da461SJens Wiklander * execution. 94aa5da461SJens Wiklander ******************************************************************************/ 9557d1e5faSMasahiro Yamada static void opteed_cpu_on_finish_handler(u_register_t unused) 96aa5da461SJens Wiklander { 97aa5da461SJens Wiklander int32_t rc = 0; 98fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 99aa5da461SJens Wiklander optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 100aa5da461SJens Wiklander entry_point_info_t optee_on_entrypoint; 101aa5da461SJens Wiklander 102776ff52aSDaniel Boulby assert(optee_vector_table); 103aa5da461SJens Wiklander assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF); 104aa5da461SJens Wiklander 105aa5da461SJens Wiklander opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw, 106776ff52aSDaniel Boulby (uint64_t)&optee_vector_table->cpu_on_entry, 10719911aa6SJens Wiklander 0, 0, 0, optee_ctx); 108aa5da461SJens Wiklander 109aa5da461SJens Wiklander /* Initialise this cpu's secure context */ 110fd650ff6SSoby Mathew cm_init_my_context(&optee_on_entrypoint); 111aa5da461SJens Wiklander 112aa5da461SJens Wiklander /* Enter OPTEE */ 113aa5da461SJens Wiklander rc = opteed_synchronous_sp_entry(optee_ctx); 114aa5da461SJens Wiklander 115aa5da461SJens Wiklander /* 116aa5da461SJens Wiklander * Read the response from OPTEE. A non-zero return means that 117aa5da461SJens Wiklander * something went wrong while communicating with OPTEE. 118aa5da461SJens Wiklander */ 119aa5da461SJens Wiklander if (rc != 0) 120aa5da461SJens Wiklander panic(); 121aa5da461SJens Wiklander 122aa5da461SJens Wiklander /* Update its context to reflect the state OPTEE is in */ 123aa5da461SJens Wiklander set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 124aa5da461SJens Wiklander } 125aa5da461SJens Wiklander 126aa5da461SJens Wiklander /******************************************************************************* 127aa5da461SJens Wiklander * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it 128aa5da461SJens Wiklander * completed the preceding suspend call. Use that context to program an entry 129aa5da461SJens Wiklander * into OPTEE to allow it to do any remaining book keeping 130aa5da461SJens Wiklander ******************************************************************************/ 13157d1e5faSMasahiro Yamada static void opteed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl) 132aa5da461SJens Wiklander { 133aa5da461SJens Wiklander int32_t rc = 0; 134fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 135aa5da461SJens Wiklander optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 136aa5da461SJens Wiklander 137776ff52aSDaniel Boulby assert(optee_vector_table); 138aa5da461SJens Wiklander assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND); 139aa5da461SJens Wiklander 140f1054c93SAchin Gupta /* Program the entry point, max_off_pwrlvl and enter the SP */ 141aa5da461SJens Wiklander write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), 142aa5da461SJens Wiklander CTX_GPREG_X0, 143f1054c93SAchin Gupta max_off_pwrlvl); 144776ff52aSDaniel Boulby cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_resume_entry); 145aa5da461SJens Wiklander rc = opteed_synchronous_sp_entry(optee_ctx); 146aa5da461SJens Wiklander 147aa5da461SJens Wiklander /* 148aa5da461SJens Wiklander * Read the response from OPTEE. A non-zero return means that 149aa5da461SJens Wiklander * something went wrong while communicating with OPTEE. 150aa5da461SJens Wiklander */ 151aa5da461SJens Wiklander if (rc != 0) 152aa5da461SJens Wiklander panic(); 153aa5da461SJens Wiklander 154aa5da461SJens Wiklander /* Update its context to reflect the state OPTEE is in */ 155aa5da461SJens Wiklander set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); 156aa5da461SJens Wiklander } 157aa5da461SJens Wiklander 158aa5da461SJens Wiklander /******************************************************************************* 159aa5da461SJens Wiklander * Return the type of OPTEE the OPTEED is dealing with. Report the current 160aa5da461SJens Wiklander * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. 161aa5da461SJens Wiklander ******************************************************************************/ 16257d1e5faSMasahiro Yamada static int32_t opteed_cpu_migrate_info(u_register_t *resident_cpu) 163aa5da461SJens Wiklander { 164aa5da461SJens Wiklander return OPTEE_MIGRATE_INFO; 165aa5da461SJens Wiklander } 166aa5da461SJens Wiklander 167aa5da461SJens Wiklander /******************************************************************************* 168aa5da461SJens Wiklander * System is about to be switched off. Allow the OPTEED/OPTEE to perform 169aa5da461SJens Wiklander * any actions needed. 170aa5da461SJens Wiklander ******************************************************************************/ 171aa5da461SJens Wiklander static void opteed_system_off(void) 172aa5da461SJens Wiklander { 173fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 174aa5da461SJens Wiklander optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 175aa5da461SJens Wiklander 176776ff52aSDaniel Boulby assert(optee_vector_table); 177aa5da461SJens Wiklander assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 178aa5da461SJens Wiklander 179aa5da461SJens Wiklander /* Program the entry point */ 180776ff52aSDaniel Boulby cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_off_entry); 181aa5da461SJens Wiklander 182aa5da461SJens Wiklander /* Enter OPTEE. We do not care about the return value because we 183aa5da461SJens Wiklander * must continue the shutdown anyway */ 184aa5da461SJens Wiklander opteed_synchronous_sp_entry(optee_ctx); 185aa5da461SJens Wiklander } 186aa5da461SJens Wiklander 187aa5da461SJens Wiklander /******************************************************************************* 188aa5da461SJens Wiklander * System is about to be reset. Allow the OPTEED/OPTEE to perform 189aa5da461SJens Wiklander * any actions needed. 190aa5da461SJens Wiklander ******************************************************************************/ 191aa5da461SJens Wiklander static void opteed_system_reset(void) 192aa5da461SJens Wiklander { 193fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 194aa5da461SJens Wiklander optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; 195aa5da461SJens Wiklander 196776ff52aSDaniel Boulby assert(optee_vector_table); 197aa5da461SJens Wiklander assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); 198aa5da461SJens Wiklander 199aa5da461SJens Wiklander /* Program the entry point */ 200776ff52aSDaniel Boulby cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_reset_entry); 201aa5da461SJens Wiklander 202aa5da461SJens Wiklander /* Enter OPTEE. We do not care about the return value because we 203aa5da461SJens Wiklander * must continue the reset anyway */ 204aa5da461SJens Wiklander opteed_synchronous_sp_entry(optee_ctx); 205aa5da461SJens Wiklander } 206aa5da461SJens Wiklander 207aa5da461SJens Wiklander 208aa5da461SJens Wiklander /******************************************************************************* 209aa5da461SJens Wiklander * Structure populated by the OPTEE Dispatcher to be given a chance to 210aa5da461SJens Wiklander * perform any OPTEE bookkeeping before PSCI executes a power mgmt. 211aa5da461SJens Wiklander * operation. 212aa5da461SJens Wiklander ******************************************************************************/ 213aa5da461SJens Wiklander const spd_pm_ops_t opteed_pm = { 214aa5da461SJens Wiklander .svc_on = opteed_cpu_on_handler, 215aa5da461SJens Wiklander .svc_off = opteed_cpu_off_handler, 216aa5da461SJens Wiklander .svc_suspend = opteed_cpu_suspend_handler, 217aa5da461SJens Wiklander .svc_on_finish = opteed_cpu_on_finish_handler, 218aa5da461SJens Wiklander .svc_suspend_finish = opteed_cpu_suspend_finish_handler, 219aa5da461SJens Wiklander .svc_migrate = NULL, 220aa5da461SJens Wiklander .svc_migrate_info = opteed_cpu_migrate_info, 221aa5da461SJens Wiklander .svc_system_off = opteed_system_off, 222aa5da461SJens Wiklander .svc_system_reset = opteed_system_reset, 223aa5da461SJens Wiklander }; 224