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 ******************************************************************************/
tspd_cpu_on_handler(u_register_t target_cpu)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 ******************************************************************************/
tspd_cpu_off_handler(u_register_t unused)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 ******************************************************************************/
tspd_cpu_suspend_handler(u_register_t max_off_pwrlvl)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 ******************************************************************************/
tspd_cpu_on_finish_handler(u_register_t unused)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 ******************************************************************************/
tspd_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl,bool abandon)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 ******************************************************************************/
tspd_cpu_migrate_info(u_register_t * resident_cpu)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 ******************************************************************************/
tspd_system_off(void)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 ******************************************************************************/
tspd_system_reset(void)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