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