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