1607084eeSAchin Gupta /* 2*04c39e46SBoyan Karatotev * Copyright (c) 2013-2025, 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> 809d40e0eSAntonio Nino Diaz 909d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1009d40e0eSAntonio Nino Diaz #include <bl32/tsp/tsp.h> 1109d40e0eSAntonio Nino Diaz #include <common/bl_common.h> 1209d40e0eSAntonio Nino Diaz #include <common/debug.h> 1309d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/context_mgmt.h> 1409d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 1509d40e0eSAntonio 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); 86*04c39e46SBoyan Karatotev 87*04c39e46SBoyan Karatotev /* Save NS context in case we need to return to it */ 88*04c39e46SBoyan Karatotev cm_el1_sysregs_context_save(NON_SECURE); 89*04c39e46SBoyan Karatotev 90607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 91607084eeSAchin Gupta 92607084eeSAchin Gupta /* 93607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 94607084eeSAchin Gupta * something went wrong while communicating with the TSP. 95607084eeSAchin Gupta */ 963df6012aSDouglas Raillard if (rc) 97607084eeSAchin Gupta panic(); 98607084eeSAchin Gupta 99607084eeSAchin Gupta /* Update its context to reflect the state the TSP is in */ 1003ee8a164SAchin Gupta set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_SUSPEND); 101607084eeSAchin Gupta } 102607084eeSAchin Gupta 103607084eeSAchin Gupta /******************************************************************************* 104607084eeSAchin Gupta * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits 1053df6012aSDouglas Raillard * before passing control back to the Secure Monitor. Entry in S-EL1 is done 106607084eeSAchin Gupta * after initialising minimal architectural state that guarantees safe 107607084eeSAchin Gupta * execution. 108607084eeSAchin Gupta ******************************************************************************/ 10957d1e5faSMasahiro Yamada static void tspd_cpu_on_finish_handler(u_register_t unused) 110607084eeSAchin Gupta { 111607084eeSAchin Gupta int32_t rc = 0; 112fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 113fb037bfbSDan Handley tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 11450e27dadSVikram Kanigiri entry_point_info_t tsp_on_entrypoint; 115607084eeSAchin Gupta 116399fb08fSAndrew Thoelke assert(tsp_vectors); 1173ee8a164SAchin Gupta assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF); 118607084eeSAchin Gupta 11950e27dadSVikram Kanigiri tspd_init_tsp_ep_state(&tsp_on_entrypoint, 120607084eeSAchin Gupta TSP_AARCH64, 12150e27dadSVikram Kanigiri (uint64_t) &tsp_vectors->cpu_on_entry, 122607084eeSAchin Gupta tsp_ctx); 123607084eeSAchin Gupta 12450e27dadSVikram Kanigiri /* Initialise this cpu's secure context */ 125fd650ff6SSoby Mathew cm_init_my_context(&tsp_on_entrypoint); 12650e27dadSVikram Kanigiri 12702446137SSoby Mathew #if TSP_NS_INTR_ASYNC_PREEMPT 128f4f1ae77SSoby Mathew /* 129f4f1ae77SSoby Mathew * Disable the NS interrupt locally since it will be enabled globally 130fd650ff6SSoby Mathew * within cm_init_my_context. 131f4f1ae77SSoby Mathew */ 132f4f1ae77SSoby Mathew disable_intr_rm_local(INTR_TYPE_NS, SECURE); 133f4f1ae77SSoby Mathew #endif 134f4f1ae77SSoby Mathew 135607084eeSAchin Gupta /* Enter the TSP */ 136607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 137607084eeSAchin Gupta 138607084eeSAchin Gupta /* 139607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 140607084eeSAchin Gupta * something went wrong while communicating with the SP. 141607084eeSAchin Gupta */ 142607084eeSAchin Gupta if (rc != 0) 143607084eeSAchin Gupta panic(); 144607084eeSAchin Gupta 145607084eeSAchin Gupta /* Update its context to reflect the state the SP is in */ 1463ee8a164SAchin Gupta set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); 147607084eeSAchin Gupta } 148607084eeSAchin Gupta 149607084eeSAchin Gupta /******************************************************************************* 150607084eeSAchin Gupta * This cpu has resumed from suspend. The SPD saved the TSP context when it 151607084eeSAchin Gupta * completed the preceding suspend call. Use that context to program an entry 152607084eeSAchin Gupta * into the TSP to allow it to do any remaining book keeping 153607084eeSAchin Gupta ******************************************************************************/ 154*04c39e46SBoyan Karatotev static void tspd_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl, bool abandon) 155607084eeSAchin Gupta { 156607084eeSAchin Gupta int32_t rc = 0; 157fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 158fb037bfbSDan Handley tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 159607084eeSAchin Gupta 160399fb08fSAndrew Thoelke assert(tsp_vectors); 1613ee8a164SAchin Gupta assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND); 162607084eeSAchin Gupta 163f1054c93SAchin Gupta /* Program the entry point, max_off_pwrlvl and enter the SP */ 164607084eeSAchin Gupta write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), 165607084eeSAchin Gupta CTX_GPREG_X0, 166f1054c93SAchin Gupta max_off_pwrlvl); 167399fb08fSAndrew Thoelke cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry); 168607084eeSAchin Gupta rc = tspd_synchronous_sp_entry(tsp_ctx); 169607084eeSAchin Gupta 170607084eeSAchin Gupta /* 171607084eeSAchin Gupta * Read the response from the TSP. A non-zero return means that 172607084eeSAchin Gupta * something went wrong while communicating with the TSP. 173607084eeSAchin Gupta */ 174607084eeSAchin Gupta if (rc != 0) 175607084eeSAchin Gupta panic(); 176607084eeSAchin Gupta 177*04c39e46SBoyan Karatotev /* We're returning back to NS so we need to put back its context */ 178*04c39e46SBoyan Karatotev if (abandon) { 179*04c39e46SBoyan Karatotev cm_el1_sysregs_context_restore(NON_SECURE); 180*04c39e46SBoyan Karatotev } 181*04c39e46SBoyan Karatotev 182607084eeSAchin Gupta /* Update its context to reflect the state the SP is in */ 1833ee8a164SAchin Gupta set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); 184607084eeSAchin Gupta } 185607084eeSAchin Gupta 186607084eeSAchin Gupta /******************************************************************************* 187607084eeSAchin Gupta * Return the type of TSP the TSPD is dealing with. Report the current resident 188607084eeSAchin Gupta * cpu (mpidr format) if it is a UP/UP migratable TSP. 189607084eeSAchin Gupta ******************************************************************************/ 19057d1e5faSMasahiro Yamada static int32_t tspd_cpu_migrate_info(u_register_t *resident_cpu) 191607084eeSAchin Gupta { 192607084eeSAchin Gupta return TSP_MIGRATE_INFO; 193607084eeSAchin Gupta } 194607084eeSAchin Gupta 195607084eeSAchin Gupta /******************************************************************************* 196d5f13093SJuan Castillo * System is about to be switched off. Allow the TSPD/TSP to perform 197d5f13093SJuan Castillo * any actions needed. 198d5f13093SJuan Castillo ******************************************************************************/ 199d5f13093SJuan Castillo static void tspd_system_off(void) 200d5f13093SJuan Castillo { 201fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 202d5f13093SJuan Castillo tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 203d5f13093SJuan Castillo 204d5f13093SJuan Castillo assert(tsp_vectors); 205d5f13093SJuan Castillo assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); 206d5f13093SJuan Castillo 2073df6012aSDouglas Raillard /* 2083df6012aSDouglas Raillard * Abort any preempted SMC request before overwriting the SECURE 2093df6012aSDouglas Raillard * context. 2103df6012aSDouglas Raillard */ 2113df6012aSDouglas Raillard tspd_abort_preempted_smc(tsp_ctx); 2123df6012aSDouglas Raillard 213d5f13093SJuan Castillo /* Program the entry point */ 214d5f13093SJuan Castillo cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_off_entry); 215d5f13093SJuan Castillo 216d5f13093SJuan Castillo /* Enter the TSP. We do not care about the return value because we 217d5f13093SJuan Castillo * must continue the shutdown anyway */ 218d5f13093SJuan Castillo tspd_synchronous_sp_entry(tsp_ctx); 219d5f13093SJuan Castillo } 220d5f13093SJuan Castillo 221d5f13093SJuan Castillo /******************************************************************************* 222d5f13093SJuan Castillo * System is about to be reset. Allow the TSPD/TSP to perform 223d5f13093SJuan Castillo * any actions needed. 224d5f13093SJuan Castillo ******************************************************************************/ 225d5f13093SJuan Castillo static void tspd_system_reset(void) 226d5f13093SJuan Castillo { 227fd650ff6SSoby Mathew uint32_t linear_id = plat_my_core_pos(); 228d5f13093SJuan Castillo tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; 229d5f13093SJuan Castillo 230d5f13093SJuan Castillo assert(tsp_vectors); 231d5f13093SJuan Castillo assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); 232d5f13093SJuan Castillo 2333df6012aSDouglas Raillard /* 2343df6012aSDouglas Raillard * Abort any preempted SMC request before overwriting the SECURE 2353df6012aSDouglas Raillard * context. 2363df6012aSDouglas Raillard */ 2373df6012aSDouglas Raillard tspd_abort_preempted_smc(tsp_ctx); 2383df6012aSDouglas Raillard 239d5f13093SJuan Castillo /* Program the entry point */ 240d5f13093SJuan Castillo cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry); 241d5f13093SJuan Castillo 2423df6012aSDouglas Raillard /* 2433df6012aSDouglas Raillard * Enter the TSP. We do not care about the return value because we 2443df6012aSDouglas Raillard * must continue the reset anyway 2453df6012aSDouglas Raillard */ 246d5f13093SJuan Castillo tspd_synchronous_sp_entry(tsp_ctx); 247d5f13093SJuan Castillo } 248d5f13093SJuan Castillo 249d5f13093SJuan Castillo /******************************************************************************* 250607084eeSAchin Gupta * Structure populated by the TSP Dispatcher to be given a chance to perform any 251607084eeSAchin Gupta * TSP bookkeeping before PSCI executes a power mgmt. operation. 252607084eeSAchin Gupta ******************************************************************************/ 253fb037bfbSDan Handley const spd_pm_ops_t tspd_pm = { 254d5f13093SJuan Castillo .svc_on = tspd_cpu_on_handler, 255d5f13093SJuan Castillo .svc_off = tspd_cpu_off_handler, 256d5f13093SJuan Castillo .svc_suspend = tspd_cpu_suspend_handler, 257d5f13093SJuan Castillo .svc_on_finish = tspd_cpu_on_finish_handler, 258d5f13093SJuan Castillo .svc_suspend_finish = tspd_cpu_suspend_finish_handler, 259d5f13093SJuan Castillo .svc_migrate = NULL, 260d5f13093SJuan Castillo .svc_migrate_info = tspd_cpu_migrate_info, 261d5f13093SJuan Castillo .svc_system_off = tspd_system_off, 262d5f13093SJuan Castillo .svc_system_reset = tspd_system_reset 263607084eeSAchin Gupta }; 264