blob: 5a1dd4fd6263f2a4bdaa0b5dcf6236223e71c15b [file] [log] [blame]
Jens Wiklanderc2888862014-08-04 15:39:58 +02001/*
Edison Ai5d685d32017-07-18 16:52:26 +08002 * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
Jens Wiklanderc2888862014-08-04 15:39:58 +02003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Jens Wiklanderc2888862014-08-04 15:39:58 +02005 */
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 "opteed_private.h"
14
15/*******************************************************************************
16 * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any
17 * actions needed. Nothing at the moment.
18 ******************************************************************************/
19static void opteed_cpu_on_handler(uint64_t target_cpu)
20{
21}
22
23/*******************************************************************************
24 * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions
25 * needed
26 ******************************************************************************/
Soby Mathewf5121572014-09-30 11:19:51 +010027static int32_t opteed_cpu_off_handler(uint64_t unused)
Jens Wiklanderc2888862014-08-04 15:39:58 +020028{
29 int32_t rc = 0;
Soby Mathewda43b662015-07-08 21:45:46 +010030 uint32_t linear_id = plat_my_core_pos();
Jens Wiklanderc2888862014-08-04 15:39:58 +020031 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
32
33 assert(optee_vectors);
34 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
35
36 /* Program the entry point and enter OPTEE */
37 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_off_entry);
38 rc = opteed_synchronous_sp_entry(optee_ctx);
39
40 /*
41 * Read the response from OPTEE. A non-zero return means that
42 * something went wrong while communicating with OPTEE.
43 */
44 if (rc != 0)
45 panic();
46
47 /*
48 * Reset OPTEE's context for a fresh start when this cpu is turned on
49 * subsequently.
50 */
51 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF);
52
53 return 0;
54}
55
56/*******************************************************************************
57 * This cpu is being suspended. S-EL1 state must have been saved in the
58 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
59 ******************************************************************************/
Achin Gupta9a0ff9b2015-09-07 20:43:27 +010060static void opteed_cpu_suspend_handler(uint64_t max_off_pwrlvl)
Jens Wiklanderc2888862014-08-04 15:39:58 +020061{
62 int32_t rc = 0;
Soby Mathewda43b662015-07-08 21:45:46 +010063 uint32_t linear_id = plat_my_core_pos();
Jens Wiklanderc2888862014-08-04 15:39:58 +020064 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
65
66 assert(optee_vectors);
67 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
68
Soby Mathewf5121572014-09-30 11:19:51 +010069 /* Program the entry point and enter OPTEE */
Jens Wiklanderc2888862014-08-04 15:39:58 +020070 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_suspend_entry);
71 rc = opteed_synchronous_sp_entry(optee_ctx);
72
73 /*
74 * Read the response from OPTEE. A non-zero return means that
75 * something went wrong while communicating with OPTEE.
76 */
77 if (rc != 0)
78 panic();
79
80 /* Update its context to reflect the state OPTEE is in */
81 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND);
82}
83
84/*******************************************************************************
85 * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits
86 * before passing control back to the Secure Monitor. Entry in S-El1 is done
87 * after initialising minimal architectural state that guarantees safe
88 * execution.
89 ******************************************************************************/
Soby Mathewf5121572014-09-30 11:19:51 +010090static void opteed_cpu_on_finish_handler(uint64_t unused)
Jens Wiklanderc2888862014-08-04 15:39:58 +020091{
92 int32_t rc = 0;
Soby Mathewda43b662015-07-08 21:45:46 +010093 uint32_t linear_id = plat_my_core_pos();
Jens Wiklanderc2888862014-08-04 15:39:58 +020094 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
95 entry_point_info_t optee_on_entrypoint;
96
97 assert(optee_vectors);
98 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF);
99
100 opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw,
101 (uint64_t)&optee_vectors->cpu_on_entry,
Edison Ai5d685d32017-07-18 16:52:26 +0800102 0, 0, optee_ctx);
Jens Wiklanderc2888862014-08-04 15:39:58 +0200103
104 /* Initialise this cpu's secure context */
Soby Mathewda43b662015-07-08 21:45:46 +0100105 cm_init_my_context(&optee_on_entrypoint);
Jens Wiklanderc2888862014-08-04 15:39:58 +0200106
107 /* Enter OPTEE */
108 rc = opteed_synchronous_sp_entry(optee_ctx);
109
110 /*
111 * Read the response from OPTEE. A non-zero return means that
112 * something went wrong while communicating with OPTEE.
113 */
114 if (rc != 0)
115 panic();
116
117 /* Update its context to reflect the state OPTEE is in */
118 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
119}
120
121/*******************************************************************************
122 * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it
123 * completed the preceding suspend call. Use that context to program an entry
124 * into OPTEE to allow it to do any remaining book keeping
125 ******************************************************************************/
Achin Gupta9a0ff9b2015-09-07 20:43:27 +0100126static void opteed_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl)
Jens Wiklanderc2888862014-08-04 15:39:58 +0200127{
128 int32_t rc = 0;
Soby Mathewda43b662015-07-08 21:45:46 +0100129 uint32_t linear_id = plat_my_core_pos();
Jens Wiklanderc2888862014-08-04 15:39:58 +0200130 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
131
132 assert(optee_vectors);
133 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND);
134
Achin Gupta9a0ff9b2015-09-07 20:43:27 +0100135 /* Program the entry point, max_off_pwrlvl and enter the SP */
Jens Wiklanderc2888862014-08-04 15:39:58 +0200136 write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
137 CTX_GPREG_X0,
Achin Gupta9a0ff9b2015-09-07 20:43:27 +0100138 max_off_pwrlvl);
Jens Wiklanderc2888862014-08-04 15:39:58 +0200139 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_resume_entry);
140 rc = opteed_synchronous_sp_entry(optee_ctx);
141
142 /*
143 * Read the response from OPTEE. A non-zero return means that
144 * something went wrong while communicating with OPTEE.
145 */
146 if (rc != 0)
147 panic();
148
149 /* Update its context to reflect the state OPTEE is in */
150 set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
151}
152
153/*******************************************************************************
154 * Return the type of OPTEE the OPTEED is dealing with. Report the current
155 * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
156 ******************************************************************************/
157static int32_t opteed_cpu_migrate_info(uint64_t *resident_cpu)
158{
159 return OPTEE_MIGRATE_INFO;
160}
161
162/*******************************************************************************
163 * System is about to be switched off. Allow the OPTEED/OPTEE to perform
164 * any actions needed.
165 ******************************************************************************/
166static void opteed_system_off(void)
167{
Soby Mathewda43b662015-07-08 21:45:46 +0100168 uint32_t linear_id = plat_my_core_pos();
Jens Wiklanderc2888862014-08-04 15:39:58 +0200169 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
170
171 assert(optee_vectors);
172 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
173
174 /* Program the entry point */
175 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_off_entry);
176
177 /* Enter OPTEE. We do not care about the return value because we
178 * must continue the shutdown anyway */
179 opteed_synchronous_sp_entry(optee_ctx);
180}
181
182/*******************************************************************************
183 * System is about to be reset. Allow the OPTEED/OPTEE to perform
184 * any actions needed.
185 ******************************************************************************/
186static void opteed_system_reset(void)
187{
Soby Mathewda43b662015-07-08 21:45:46 +0100188 uint32_t linear_id = plat_my_core_pos();
Jens Wiklanderc2888862014-08-04 15:39:58 +0200189 optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
190
191 assert(optee_vectors);
192 assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
193
194 /* Program the entry point */
195 cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_reset_entry);
196
197 /* Enter OPTEE. We do not care about the return value because we
198 * must continue the reset anyway */
199 opteed_synchronous_sp_entry(optee_ctx);
200}
201
202
203/*******************************************************************************
204 * Structure populated by the OPTEE Dispatcher to be given a chance to
205 * perform any OPTEE bookkeeping before PSCI executes a power mgmt.
206 * operation.
207 ******************************************************************************/
208const spd_pm_ops_t opteed_pm = {
209 .svc_on = opteed_cpu_on_handler,
210 .svc_off = opteed_cpu_off_handler,
211 .svc_suspend = opteed_cpu_suspend_handler,
212 .svc_on_finish = opteed_cpu_on_finish_handler,
213 .svc_suspend_finish = opteed_cpu_suspend_finish_handler,
214 .svc_migrate = NULL,
215 .svc_migrate_info = opteed_cpu_migrate_info,
216 .svc_system_off = opteed_system_off,
217 .svc_system_reset = opteed_system_reset,
218};