1607084eeSAchin Gupta /* 23df6012aSDouglas Raillard * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. 3607084eeSAchin Gupta * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5607084eeSAchin Gupta */ 6607084eeSAchin Gupta 797043ac9SDan Handley #include <assert.h> 8*09d40e0eSAntonio Nino Diaz 9*09d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 10*09d40e0eSAntonio Nino Diaz #include <bl32/tsp/tsp.h> 11*09d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 12*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 13*09d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/context_mgmt.h> 14*09d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 15*09d40e0eSAntonio Nino Diaz 1635e98e55SDan Handley #include "tspd_private.h" 17607084eeSAchin Gupta 18607084eeSAchin Gupta /******************************************************************************* 19607084eeSAchin Gupta * The target cpu is being turned on. Allow the TSPD/TSP to perform any actions 20607084eeSAchin Gupta * needed. Nothing at the moment. 21607084eeSAchin Gupta ******************************************************************************/ 2257d1e5faSMasahiro Yamada static void tspd_cpu_on_handler(u_register_t target_cpu) 23607084eeSAchin Gupta { 24607084eeSAchin Gupta } 25607084eeSAchin Gupta 26607084eeSAchin Gupta /******************************************************************************* 27607084eeSAchin Gupta * This cpu is being turned off. Allow the TSPD/TSP to perform any actions 28607084eeSAchin Gupta * needed 29607084eeSAchin Gupta ******************************************************************************/ 3057d1e5faSMasahiro Yamada static int32_t tspd_cpu_off_handler(u_register_t unused) 31607084eeSAchin Gupta { 32607084eeSAchin Gupta int32_t rc = 0; 33fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 34fb037bfbSDan Handley tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 35607084eeSAchin Gupta 36399fb08fSAndrew Thoelke assert(tsp_vectors); 373ee8a164SAchin Gupta assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); 38607084eeSAchin Gupta 393df6012aSDouglas Raillard /* 403df6012aSDouglas Raillard * Abort any preempted SMC request before overwriting the SECURE 413df6012aSDouglas Raillard * context. 423df6012aSDouglas Raillard */ 433df6012aSDouglas Raillard tspd_abort_preempted_smc(tsp_ctx); 443df6012aSDouglas Raillard 45607084eeSAchin Gupta /* Program the entry point and enter the TSP */ 46399fb08fSAndrew Thoelke cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_off_entry); 47607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 48607084eeSAchin Gupta 49607084eeSAchin Gupta /* 50607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 51607084eeSAchin Gupta * something went wrong while communicating with the TSP. 52607084eeSAchin Gupta */ 53607084eeSAchin Gupta if (rc != 0) 54607084eeSAchin Gupta panic(); 55607084eeSAchin Gupta 56607084eeSAchin Gupta /* 57607084eeSAchin Gupta * Reset TSP's context for a fresh start when this cpu is turned on 58607084eeSAchin Gupta * subsequently. 59607084eeSAchin Gupta */ 603ee8a164SAchin Gupta set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF); 61607084eeSAchin Gupta 62607084eeSAchin Gupta return 0; 63607084eeSAchin Gupta } 64607084eeSAchin Gupta 65607084eeSAchin Gupta /******************************************************************************* 66607084eeSAchin Gupta * This cpu is being suspended. S-EL1 state must have been saved in the 67607084eeSAchin Gupta * resident cpu (mpidr format) if it is a UP/UP migratable TSP. 68607084eeSAchin Gupta ******************************************************************************/ 6957d1e5faSMasahiro Yamada static void tspd_cpu_suspend_handler(u_register_t max_off_pwrlvl) 70607084eeSAchin Gupta { 71607084eeSAchin Gupta int32_t rc = 0; 72fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 73fb037bfbSDan Handley tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 74607084eeSAchin Gupta 75399fb08fSAndrew Thoelke assert(tsp_vectors); 763ee8a164SAchin Gupta assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); 77607084eeSAchin Gupta 783df6012aSDouglas Raillard /* 793df6012aSDouglas Raillard * Abort any preempted SMC request before overwriting the SECURE 803df6012aSDouglas Raillard * context. 813df6012aSDouglas Raillard */ 823df6012aSDouglas Raillard tspd_abort_preempted_smc(tsp_ctx); 833df6012aSDouglas Raillard 8431244d74SSoby Mathew /* Program the entry point and enter the TSP */ 85399fb08fSAndrew Thoelke cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_suspend_entry); 86607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 87607084eeSAchin Gupta 88607084eeSAchin Gupta /* 89607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 90607084eeSAchin Gupta * something went wrong while communicating with the TSP. 91607084eeSAchin Gupta */ 923df6012aSDouglas Raillard if (rc) 93607084eeSAchin Gupta panic(); 94607084eeSAchin Gupta 95607084eeSAchin Gupta /* Update its context to reflect the state the TSP is in */ 963ee8a164SAchin Gupta set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_SUSPEND); 97607084eeSAchin Gupta } 98607084eeSAchin Gupta 99607084eeSAchin Gupta /******************************************************************************* 100607084eeSAchin Gupta * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits 1013df6012aSDouglas Raillard * before passing control back to the Secure Monitor. Entry in S-EL1 is done 102607084eeSAchin Gupta * after initialising minimal architectural state that guarantees safe 103607084eeSAchin Gupta * execution. 104607084eeSAchin Gupta ******************************************************************************/ 10557d1e5faSMasahiro Yamada static void tspd_cpu_on_finish_handler(u_register_t unused) 106607084eeSAchin Gupta { 107607084eeSAchin Gupta int32_t rc = 0; 108fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 109fb037bfbSDan Handley tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 11050e27dadSVikram Kanigiri entry_point_info_t tsp_on_entrypoint; 111607084eeSAchin Gupta 112399fb08fSAndrew Thoelke assert(tsp_vectors); 1133ee8a164SAchin Gupta assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF); 114607084eeSAchin Gupta 11550e27dadSVikram Kanigiri tspd_init_tsp_ep_state(&tsp_on_entrypoint, 116607084eeSAchin Gupta TSP_AARCH64, 11750e27dadSVikram Kanigiri (uint64_t) &tsp_vectors->cpu_on_entry, 118607084eeSAchin Gupta tsp_ctx); 119607084eeSAchin Gupta 12050e27dadSVikram Kanigiri /* Initialise this cpu's secure context */ 121fd650ff6SSoby Mathew cm_init_my_context(&tsp_on_entrypoint); 12250e27dadSVikram Kanigiri 12302446137SSoby Mathew #if TSP_NS_INTR_ASYNC_PREEMPT 124f4f1ae77SSoby Mathew /* 125f4f1ae77SSoby Mathew * Disable the NS interrupt locally since it will be enabled globally 126fd650ff6SSoby Mathew * within cm_init_my_context. 127f4f1ae77SSoby Mathew */ 128f4f1ae77SSoby Mathew disable_intr_rm_local(INTR_TYPE_NS, SECURE); 129f4f1ae77SSoby Mathew #endif 130f4f1ae77SSoby Mathew 131607084eeSAchin Gupta /* Enter the TSP */ 132607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 133607084eeSAchin Gupta 134607084eeSAchin Gupta /* 135607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 136607084eeSAchin Gupta * something went wrong while communicating with the SP. 137607084eeSAchin Gupta */ 138607084eeSAchin Gupta if (rc != 0) 139607084eeSAchin Gupta panic(); 140607084eeSAchin Gupta 141607084eeSAchin Gupta /* Update its context to reflect the state the SP is in */ 1423ee8a164SAchin Gupta set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); 143607084eeSAchin Gupta } 144607084eeSAchin Gupta 145607084eeSAchin Gupta /******************************************************************************* 146607084eeSAchin Gupta * This cpu has resumed from suspend. The SPD saved the TSP context when it 147607084eeSAchin Gupta * completed the preceding suspend call. Use that context to program an entry 148607084eeSAchin Gupta * into the TSP to allow it to do any remaining book keeping 149607084eeSAchin Gupta ******************************************************************************/ 15057d1e5faSMasahiro Yamada static void tspd_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl) 151607084eeSAchin Gupta { 152607084eeSAchin Gupta int32_t rc = 0; 153fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 154fb037bfbSDan Handley tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 155607084eeSAchin Gupta 156399fb08fSAndrew Thoelke assert(tsp_vectors); 1573ee8a164SAchin Gupta assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND); 158607084eeSAchin Gupta 159f1054c93SAchin Gupta /* Program the entry point, max_off_pwrlvl and enter the SP */ 160607084eeSAchin Gupta write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), 161607084eeSAchin Gupta CTX_GPREG_X0, 162f1054c93SAchin Gupta max_off_pwrlvl); 163399fb08fSAndrew Thoelke cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry); 164607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 165607084eeSAchin Gupta 166607084eeSAchin Gupta /* 167607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 168607084eeSAchin Gupta * something went wrong while communicating with the TSP. 169607084eeSAchin Gupta */ 170607084eeSAchin Gupta if (rc != 0) 171607084eeSAchin Gupta panic(); 172607084eeSAchin Gupta 173607084eeSAchin Gupta /* Update its context to reflect the state the SP is in */ 1743ee8a164SAchin Gupta set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); 175607084eeSAchin Gupta } 176607084eeSAchin Gupta 177607084eeSAchin Gupta /******************************************************************************* 178607084eeSAchin Gupta * Return the type of TSP the TSPD is dealing with. Report the current resident 179607084eeSAchin Gupta * cpu (mpidr format) if it is a UP/UP migratable TSP. 180607084eeSAchin Gupta ******************************************************************************/ 18157d1e5faSMasahiro Yamada static int32_t tspd_cpu_migrate_info(u_register_t *resident_cpu) 182607084eeSAchin Gupta { 183607084eeSAchin Gupta return TSP_MIGRATE_INFO; 184607084eeSAchin Gupta } 185607084eeSAchin Gupta 186607084eeSAchin Gupta /******************************************************************************* 187d5f13093SJuan Castillo * System is about to be switched off. Allow the TSPD/TSP to perform 188d5f13093SJuan Castillo * any actions needed. 189d5f13093SJuan Castillo ******************************************************************************/ 190d5f13093SJuan Castillo static void tspd_system_off(void) 191d5f13093SJuan Castillo { 192fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 193d5f13093SJuan Castillo tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 194d5f13093SJuan Castillo 195d5f13093SJuan Castillo assert(tsp_vectors); 196d5f13093SJuan Castillo assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); 197d5f13093SJuan Castillo 1983df6012aSDouglas Raillard /* 1993df6012aSDouglas Raillard * Abort any preempted SMC request before overwriting the SECURE 2003df6012aSDouglas Raillard * context. 2013df6012aSDouglas Raillard */ 2023df6012aSDouglas Raillard tspd_abort_preempted_smc(tsp_ctx); 2033df6012aSDouglas Raillard 204d5f13093SJuan Castillo /* Program the entry point */ 205d5f13093SJuan Castillo cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_off_entry); 206d5f13093SJuan Castillo 207d5f13093SJuan Castillo /* Enter the TSP. We do not care about the return value because we 208d5f13093SJuan Castillo * must continue the shutdown anyway */ 209d5f13093SJuan Castillo tspd_synchronous_sp_entry(tsp_ctx); 210d5f13093SJuan Castillo } 211d5f13093SJuan Castillo 212d5f13093SJuan Castillo /******************************************************************************* 213d5f13093SJuan Castillo * System is about to be reset. Allow the TSPD/TSP to perform 214d5f13093SJuan Castillo * any actions needed. 215d5f13093SJuan Castillo ******************************************************************************/ 216d5f13093SJuan Castillo static void tspd_system_reset(void) 217d5f13093SJuan Castillo { 218fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 219d5f13093SJuan Castillo tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 220d5f13093SJuan Castillo 221d5f13093SJuan Castillo assert(tsp_vectors); 222d5f13093SJuan Castillo assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); 223d5f13093SJuan Castillo 2243df6012aSDouglas Raillard /* 2253df6012aSDouglas Raillard * Abort any preempted SMC request before overwriting the SECURE 2263df6012aSDouglas Raillard * context. 2273df6012aSDouglas Raillard */ 2283df6012aSDouglas Raillard tspd_abort_preempted_smc(tsp_ctx); 2293df6012aSDouglas Raillard 230d5f13093SJuan Castillo /* Program the entry point */ 231d5f13093SJuan Castillo cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry); 232d5f13093SJuan Castillo 2333df6012aSDouglas Raillard /* 2343df6012aSDouglas Raillard * Enter the TSP. We do not care about the return value because we 2353df6012aSDouglas Raillard * must continue the reset anyway 2363df6012aSDouglas Raillard */ 237d5f13093SJuan Castillo tspd_synchronous_sp_entry(tsp_ctx); 238d5f13093SJuan Castillo } 239d5f13093SJuan Castillo 240d5f13093SJuan Castillo /******************************************************************************* 241607084eeSAchin Gupta * Structure populated by the TSP Dispatcher to be given a chance to perform any 242607084eeSAchin Gupta * TSP bookkeeping before PSCI executes a power mgmt. operation. 243607084eeSAchin Gupta ******************************************************************************/ 244fb037bfbSDan Handley const spd_pm_ops_t tspd_pm = { 245d5f13093SJuan Castillo .svc_on = tspd_cpu_on_handler, 246d5f13093SJuan Castillo .svc_off = tspd_cpu_off_handler, 247d5f13093SJuan Castillo .svc_suspend = tspd_cpu_suspend_handler, 248d5f13093SJuan Castillo .svc_on_finish = tspd_cpu_on_finish_handler, 249d5f13093SJuan Castillo .svc_suspend_finish = tspd_cpu_suspend_finish_handler, 250d5f13093SJuan Castillo .svc_migrate = NULL, 251d5f13093SJuan Castillo .svc_migrate_info = tspd_cpu_migrate_info, 252d5f13093SJuan Castillo .svc_system_off = tspd_system_off, 253d5f13093SJuan Castillo .svc_system_reset = tspd_system_reset 254607084eeSAchin Gupta }; 255