xref: /aosp_15_r20/external/arm-trusted-firmware/services/spd/tspd/tspd_pm.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <assert.h>
8*54fd6939SJiyong Park 
9*54fd6939SJiyong Park #include <arch_helpers.h>
10*54fd6939SJiyong Park #include <bl32/tsp/tsp.h>
11*54fd6939SJiyong Park #include <common/bl_common.h>
12*54fd6939SJiyong Park #include <common/debug.h>
13*54fd6939SJiyong Park #include <lib/el3_runtime/context_mgmt.h>
14*54fd6939SJiyong Park #include <plat/common/platform.h>
15*54fd6939SJiyong Park 
16*54fd6939SJiyong Park #include "tspd_private.h"
17*54fd6939SJiyong Park 
18*54fd6939SJiyong Park /*******************************************************************************
19*54fd6939SJiyong Park  * The target cpu is being turned on. Allow the TSPD/TSP to perform any actions
20*54fd6939SJiyong Park  * needed. Nothing at the moment.
21*54fd6939SJiyong Park  ******************************************************************************/
tspd_cpu_on_handler(u_register_t target_cpu)22*54fd6939SJiyong Park static void tspd_cpu_on_handler(u_register_t target_cpu)
23*54fd6939SJiyong Park {
24*54fd6939SJiyong Park }
25*54fd6939SJiyong Park 
26*54fd6939SJiyong Park /*******************************************************************************
27*54fd6939SJiyong Park  * This cpu is being turned off. Allow the TSPD/TSP to perform any actions
28*54fd6939SJiyong Park  * needed
29*54fd6939SJiyong Park  ******************************************************************************/
tspd_cpu_off_handler(u_register_t unused)30*54fd6939SJiyong Park static int32_t tspd_cpu_off_handler(u_register_t unused)
31*54fd6939SJiyong Park {
32*54fd6939SJiyong Park 	int32_t rc = 0;
33*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos();
34*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
35*54fd6939SJiyong Park 
36*54fd6939SJiyong Park 	assert(tsp_vectors);
37*54fd6939SJiyong Park 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
38*54fd6939SJiyong Park 
39*54fd6939SJiyong Park 	/*
40*54fd6939SJiyong Park 	 * Abort any preempted SMC request before overwriting the SECURE
41*54fd6939SJiyong Park 	 * context.
42*54fd6939SJiyong Park 	 */
43*54fd6939SJiyong Park 	tspd_abort_preempted_smc(tsp_ctx);
44*54fd6939SJiyong Park 
45*54fd6939SJiyong Park 	/* Program the entry point and enter the TSP */
46*54fd6939SJiyong Park 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_off_entry);
47*54fd6939SJiyong Park 	rc = tspd_synchronous_sp_entry(tsp_ctx);
48*54fd6939SJiyong Park 
49*54fd6939SJiyong Park 	/*
50*54fd6939SJiyong Park 	 * Read the response from the TSP. A non-zero return means that
51*54fd6939SJiyong Park 	 * something went wrong while communicating with the TSP.
52*54fd6939SJiyong Park 	 */
53*54fd6939SJiyong Park 	if (rc != 0)
54*54fd6939SJiyong Park 		panic();
55*54fd6939SJiyong Park 
56*54fd6939SJiyong Park 	/*
57*54fd6939SJiyong Park 	 * Reset TSP's context for a fresh start when this cpu is turned on
58*54fd6939SJiyong Park 	 * subsequently.
59*54fd6939SJiyong Park 	 */
60*54fd6939SJiyong Park 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF);
61*54fd6939SJiyong Park 
62*54fd6939SJiyong Park 	return 0;
63*54fd6939SJiyong Park }
64*54fd6939SJiyong Park 
65*54fd6939SJiyong Park /*******************************************************************************
66*54fd6939SJiyong Park  * This cpu is being suspended. S-EL1 state must have been saved in the
67*54fd6939SJiyong Park  * resident cpu (mpidr format) if it is a UP/UP migratable TSP.
68*54fd6939SJiyong Park  ******************************************************************************/
tspd_cpu_suspend_handler(u_register_t max_off_pwrlvl)69*54fd6939SJiyong Park static void tspd_cpu_suspend_handler(u_register_t max_off_pwrlvl)
70*54fd6939SJiyong Park {
71*54fd6939SJiyong Park 	int32_t rc = 0;
72*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos();
73*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
74*54fd6939SJiyong Park 
75*54fd6939SJiyong Park 	assert(tsp_vectors);
76*54fd6939SJiyong Park 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
77*54fd6939SJiyong Park 
78*54fd6939SJiyong Park 	/*
79*54fd6939SJiyong Park 	 * Abort any preempted SMC request before overwriting the SECURE
80*54fd6939SJiyong Park 	 * context.
81*54fd6939SJiyong Park 	 */
82*54fd6939SJiyong Park 	tspd_abort_preempted_smc(tsp_ctx);
83*54fd6939SJiyong Park 
84*54fd6939SJiyong Park 	/* Program the entry point and enter the TSP */
85*54fd6939SJiyong Park 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_suspend_entry);
86*54fd6939SJiyong Park 	rc = tspd_synchronous_sp_entry(tsp_ctx);
87*54fd6939SJiyong Park 
88*54fd6939SJiyong Park 	/*
89*54fd6939SJiyong Park 	 * Read the response from the TSP. A non-zero return means that
90*54fd6939SJiyong Park 	 * something went wrong while communicating with the TSP.
91*54fd6939SJiyong Park 	 */
92*54fd6939SJiyong Park 	if (rc)
93*54fd6939SJiyong Park 		panic();
94*54fd6939SJiyong Park 
95*54fd6939SJiyong Park 	/* Update its context to reflect the state the TSP is in */
96*54fd6939SJiyong Park 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_SUSPEND);
97*54fd6939SJiyong Park }
98*54fd6939SJiyong Park 
99*54fd6939SJiyong Park /*******************************************************************************
100*54fd6939SJiyong Park  * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits
101*54fd6939SJiyong Park  * before passing control back to the Secure Monitor. Entry in S-EL1 is done
102*54fd6939SJiyong Park  * after initialising minimal architectural state that guarantees safe
103*54fd6939SJiyong Park  * execution.
104*54fd6939SJiyong Park  ******************************************************************************/
tspd_cpu_on_finish_handler(u_register_t unused)105*54fd6939SJiyong Park static void tspd_cpu_on_finish_handler(u_register_t unused)
106*54fd6939SJiyong Park {
107*54fd6939SJiyong Park 	int32_t rc = 0;
108*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos();
109*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
110*54fd6939SJiyong Park 	entry_point_info_t tsp_on_entrypoint;
111*54fd6939SJiyong Park 
112*54fd6939SJiyong Park 	assert(tsp_vectors);
113*54fd6939SJiyong Park 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF);
114*54fd6939SJiyong Park 
115*54fd6939SJiyong Park 	tspd_init_tsp_ep_state(&tsp_on_entrypoint,
116*54fd6939SJiyong Park 				TSP_AARCH64,
117*54fd6939SJiyong Park 				(uint64_t) &tsp_vectors->cpu_on_entry,
118*54fd6939SJiyong Park 				tsp_ctx);
119*54fd6939SJiyong Park 
120*54fd6939SJiyong Park 	/* Initialise this cpu's secure context */
121*54fd6939SJiyong Park 	cm_init_my_context(&tsp_on_entrypoint);
122*54fd6939SJiyong Park 
123*54fd6939SJiyong Park #if TSP_NS_INTR_ASYNC_PREEMPT
124*54fd6939SJiyong Park 	/*
125*54fd6939SJiyong Park 	 * Disable the NS interrupt locally since it will be enabled globally
126*54fd6939SJiyong Park 	 * within cm_init_my_context.
127*54fd6939SJiyong Park 	 */
128*54fd6939SJiyong Park 	disable_intr_rm_local(INTR_TYPE_NS, SECURE);
129*54fd6939SJiyong Park #endif
130*54fd6939SJiyong Park 
131*54fd6939SJiyong Park 	/* Enter the TSP */
132*54fd6939SJiyong Park 	rc = tspd_synchronous_sp_entry(tsp_ctx);
133*54fd6939SJiyong Park 
134*54fd6939SJiyong Park 	/*
135*54fd6939SJiyong Park 	 * Read the response from the TSP. A non-zero return means that
136*54fd6939SJiyong Park 	 * something went wrong while communicating with the SP.
137*54fd6939SJiyong Park 	 */
138*54fd6939SJiyong Park 	if (rc != 0)
139*54fd6939SJiyong Park 		panic();
140*54fd6939SJiyong Park 
141*54fd6939SJiyong Park 	/* Update its context to reflect the state the SP is in */
142*54fd6939SJiyong Park 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
143*54fd6939SJiyong Park }
144*54fd6939SJiyong Park 
145*54fd6939SJiyong Park /*******************************************************************************
146*54fd6939SJiyong Park  * This cpu has resumed from suspend. The SPD saved the TSP context when it
147*54fd6939SJiyong Park  * completed the preceding suspend call. Use that context to program an entry
148*54fd6939SJiyong Park  * into the TSP to allow it to do any remaining book keeping
149*54fd6939SJiyong Park  ******************************************************************************/
tspd_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl)150*54fd6939SJiyong Park static void tspd_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl)
151*54fd6939SJiyong Park {
152*54fd6939SJiyong Park 	int32_t rc = 0;
153*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos();
154*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
155*54fd6939SJiyong Park 
156*54fd6939SJiyong Park 	assert(tsp_vectors);
157*54fd6939SJiyong Park 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND);
158*54fd6939SJiyong Park 
159*54fd6939SJiyong Park 	/* Program the entry point, max_off_pwrlvl and enter the SP */
160*54fd6939SJiyong Park 	write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx),
161*54fd6939SJiyong Park 		      CTX_GPREG_X0,
162*54fd6939SJiyong Park 		      max_off_pwrlvl);
163*54fd6939SJiyong Park 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry);
164*54fd6939SJiyong Park 	rc = tspd_synchronous_sp_entry(tsp_ctx);
165*54fd6939SJiyong Park 
166*54fd6939SJiyong Park 	/*
167*54fd6939SJiyong Park 	 * Read the response from the TSP. A non-zero return means that
168*54fd6939SJiyong Park 	 * something went wrong while communicating with the TSP.
169*54fd6939SJiyong Park 	 */
170*54fd6939SJiyong Park 	if (rc != 0)
171*54fd6939SJiyong Park 		panic();
172*54fd6939SJiyong Park 
173*54fd6939SJiyong Park 	/* Update its context to reflect the state the SP is in */
174*54fd6939SJiyong Park 	set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON);
175*54fd6939SJiyong Park }
176*54fd6939SJiyong Park 
177*54fd6939SJiyong Park /*******************************************************************************
178*54fd6939SJiyong Park  * Return the type of TSP the TSPD is dealing with. Report the current resident
179*54fd6939SJiyong Park  * cpu (mpidr format) if it is a UP/UP migratable TSP.
180*54fd6939SJiyong Park  ******************************************************************************/
tspd_cpu_migrate_info(u_register_t * resident_cpu)181*54fd6939SJiyong Park static int32_t tspd_cpu_migrate_info(u_register_t *resident_cpu)
182*54fd6939SJiyong Park {
183*54fd6939SJiyong Park 	return TSP_MIGRATE_INFO;
184*54fd6939SJiyong Park }
185*54fd6939SJiyong Park 
186*54fd6939SJiyong Park /*******************************************************************************
187*54fd6939SJiyong Park  * System is about to be switched off. Allow the TSPD/TSP to perform
188*54fd6939SJiyong Park  * any actions needed.
189*54fd6939SJiyong Park  ******************************************************************************/
tspd_system_off(void)190*54fd6939SJiyong Park static void tspd_system_off(void)
191*54fd6939SJiyong Park {
192*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos();
193*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
194*54fd6939SJiyong Park 
195*54fd6939SJiyong Park 	assert(tsp_vectors);
196*54fd6939SJiyong Park 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
197*54fd6939SJiyong Park 
198*54fd6939SJiyong Park 	/*
199*54fd6939SJiyong Park 	 * Abort any preempted SMC request before overwriting the SECURE
200*54fd6939SJiyong Park 	 * context.
201*54fd6939SJiyong Park 	 */
202*54fd6939SJiyong Park 	tspd_abort_preempted_smc(tsp_ctx);
203*54fd6939SJiyong Park 
204*54fd6939SJiyong Park 	/* Program the entry point */
205*54fd6939SJiyong Park 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_off_entry);
206*54fd6939SJiyong Park 
207*54fd6939SJiyong Park 	/* Enter the TSP. We do not care about the return value because we
208*54fd6939SJiyong Park 	 * must continue the shutdown anyway */
209*54fd6939SJiyong Park 	tspd_synchronous_sp_entry(tsp_ctx);
210*54fd6939SJiyong Park }
211*54fd6939SJiyong Park 
212*54fd6939SJiyong Park /*******************************************************************************
213*54fd6939SJiyong Park  * System is about to be reset. Allow the TSPD/TSP to perform
214*54fd6939SJiyong Park  * any actions needed.
215*54fd6939SJiyong Park  ******************************************************************************/
tspd_system_reset(void)216*54fd6939SJiyong Park static void tspd_system_reset(void)
217*54fd6939SJiyong Park {
218*54fd6939SJiyong Park 	uint32_t linear_id = plat_my_core_pos();
219*54fd6939SJiyong Park 	tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id];
220*54fd6939SJiyong Park 
221*54fd6939SJiyong Park 	assert(tsp_vectors);
222*54fd6939SJiyong Park 	assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON);
223*54fd6939SJiyong Park 
224*54fd6939SJiyong Park 	/*
225*54fd6939SJiyong Park 	 * Abort any preempted SMC request before overwriting the SECURE
226*54fd6939SJiyong Park 	 * context.
227*54fd6939SJiyong Park 	 */
228*54fd6939SJiyong Park 	tspd_abort_preempted_smc(tsp_ctx);
229*54fd6939SJiyong Park 
230*54fd6939SJiyong Park 	/* Program the entry point */
231*54fd6939SJiyong Park 	cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry);
232*54fd6939SJiyong Park 
233*54fd6939SJiyong Park 	/*
234*54fd6939SJiyong Park 	 * Enter the TSP. We do not care about the return value because we
235*54fd6939SJiyong Park 	 * must continue the reset anyway
236*54fd6939SJiyong Park 	 */
237*54fd6939SJiyong Park 	tspd_synchronous_sp_entry(tsp_ctx);
238*54fd6939SJiyong Park }
239*54fd6939SJiyong Park 
240*54fd6939SJiyong Park /*******************************************************************************
241*54fd6939SJiyong Park  * Structure populated by the TSP Dispatcher to be given a chance to perform any
242*54fd6939SJiyong Park  * TSP bookkeeping before PSCI executes a power mgmt.  operation.
243*54fd6939SJiyong Park  ******************************************************************************/
244*54fd6939SJiyong Park const spd_pm_ops_t tspd_pm = {
245*54fd6939SJiyong Park 	.svc_on = tspd_cpu_on_handler,
246*54fd6939SJiyong Park 	.svc_off = tspd_cpu_off_handler,
247*54fd6939SJiyong Park 	.svc_suspend = tspd_cpu_suspend_handler,
248*54fd6939SJiyong Park 	.svc_on_finish = tspd_cpu_on_finish_handler,
249*54fd6939SJiyong Park 	.svc_suspend_finish = tspd_cpu_suspend_finish_handler,
250*54fd6939SJiyong Park 	.svc_migrate = NULL,
251*54fd6939SJiyong Park 	.svc_migrate_info = tspd_cpu_migrate_info,
252*54fd6939SJiyong Park 	.svc_system_off = tspd_system_off,
253*54fd6939SJiyong Park 	.svc_system_reset = tspd_system_reset
254*54fd6939SJiyong Park };
255