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