xref: /rk3399_ARM-atf/services/spd/opteed/opteed_pm.c (revision aa5da46138e1583990086b76b56e0a9186cb7b7d)
1*aa5da461SJens Wiklander /*
2*aa5da461SJens Wiklander  * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
3*aa5da461SJens Wiklander  *
4*aa5da461SJens Wiklander  * Redistribution and use in source and binary forms, with or without
5*aa5da461SJens Wiklander  * modification, are permitted provided that the following conditions are met:
6*aa5da461SJens Wiklander  *
7*aa5da461SJens Wiklander  * Redistributions of source code must retain the above copyright notice, this
8*aa5da461SJens Wiklander  * list of conditions and the following disclaimer.
9*aa5da461SJens Wiklander  *
10*aa5da461SJens Wiklander  * Redistributions in binary form must reproduce the above copyright notice,
11*aa5da461SJens Wiklander  * this list of conditions and the following disclaimer in the documentation
12*aa5da461SJens Wiklander  * and/or other materials provided with the distribution.
13*aa5da461SJens Wiklander  *
14*aa5da461SJens Wiklander  * Neither the name of ARM nor the names of its contributors may be used
15*aa5da461SJens Wiklander  * to endorse or promote products derived from this software without specific
16*aa5da461SJens Wiklander  * prior written permission.
17*aa5da461SJens Wiklander  *
18*aa5da461SJens Wiklander  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*aa5da461SJens Wiklander  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*aa5da461SJens Wiklander  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*aa5da461SJens Wiklander  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*aa5da461SJens Wiklander  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*aa5da461SJens Wiklander  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*aa5da461SJens Wiklander  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*aa5da461SJens Wiklander  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*aa5da461SJens Wiklander  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*aa5da461SJens Wiklander  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*aa5da461SJens Wiklander  * POSSIBILITY OF SUCH DAMAGE.
29*aa5da461SJens Wiklander  */
30*aa5da461SJens Wiklander 
31*aa5da461SJens Wiklander #include <arch_helpers.h>
32*aa5da461SJens Wiklander #include <assert.h>
33*aa5da461SJens Wiklander #include <bl_common.h>
34*aa5da461SJens Wiklander #include <context_mgmt.h>
35*aa5da461SJens Wiklander #include <debug.h>
36*aa5da461SJens Wiklander #include <platform.h>
37*aa5da461SJens Wiklander #include "opteed_private.h"
38*aa5da461SJens Wiklander 
39*aa5da461SJens Wiklander /*******************************************************************************
40*aa5da461SJens Wiklander  * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any
41*aa5da461SJens Wiklander  * actions needed. Nothing at the moment.
42*aa5da461SJens Wiklander  ******************************************************************************/
43*aa5da461SJens Wiklander static void opteed_cpu_on_handler(uint64_t target_cpu)
44*aa5da461SJens Wiklander {
45*aa5da461SJens Wiklander }
46*aa5da461SJens Wiklander 
47*aa5da461SJens Wiklander /*******************************************************************************
48*aa5da461SJens Wiklander  * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions
49*aa5da461SJens Wiklander  * needed
50*aa5da461SJens Wiklander  ******************************************************************************/
51*aa5da461SJens Wiklander static int32_t opteed_cpu_off_handler(uint64_t cookie)
52*aa5da461SJens Wiklander {
53*aa5da461SJens Wiklander 	int32_t rc = 0;
54*aa5da461SJens Wiklander 	uint64_t mpidr = read_mpidr();
55*aa5da461SJens Wiklander 	uint32_t linear_id = platform_get_core_pos(mpidr);
56*aa5da461SJens Wiklander 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
57*aa5da461SJens Wiklander 
58*aa5da461SJens Wiklander 	assert(optee_vectors);
59*aa5da461SJens Wiklander 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
60*aa5da461SJens Wiklander 
61*aa5da461SJens Wiklander 	/* Program the entry point and enter OPTEE */
62*aa5da461SJens Wiklander 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_off_entry);
63*aa5da461SJens Wiklander 	rc = opteed_synchronous_sp_entry(optee_ctx);
64*aa5da461SJens Wiklander 
65*aa5da461SJens Wiklander 	/*
66*aa5da461SJens Wiklander 	 * Read the response from OPTEE. A non-zero return means that
67*aa5da461SJens Wiklander 	 * something went wrong while communicating with OPTEE.
68*aa5da461SJens Wiklander 	 */
69*aa5da461SJens Wiklander 	if (rc != 0)
70*aa5da461SJens Wiklander 		panic();
71*aa5da461SJens Wiklander 
72*aa5da461SJens Wiklander 	/*
73*aa5da461SJens Wiklander 	 * Reset OPTEE's context for a fresh start when this cpu is turned on
74*aa5da461SJens Wiklander 	 * subsequently.
75*aa5da461SJens Wiklander 	 */
76*aa5da461SJens Wiklander 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF);
77*aa5da461SJens Wiklander 
78*aa5da461SJens Wiklander 	 return 0;
79*aa5da461SJens Wiklander }
80*aa5da461SJens Wiklander 
81*aa5da461SJens Wiklander /*******************************************************************************
82*aa5da461SJens Wiklander  * This cpu is being suspended. S-EL1 state must have been saved in the
83*aa5da461SJens Wiklander  * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
84*aa5da461SJens Wiklander  ******************************************************************************/
85*aa5da461SJens Wiklander static void opteed_cpu_suspend_handler(uint64_t power_state)
86*aa5da461SJens Wiklander {
87*aa5da461SJens Wiklander 	int32_t rc = 0;
88*aa5da461SJens Wiklander 	uint64_t mpidr = read_mpidr();
89*aa5da461SJens Wiklander 	uint32_t linear_id = platform_get_core_pos(mpidr);
90*aa5da461SJens Wiklander 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
91*aa5da461SJens Wiklander 
92*aa5da461SJens Wiklander 	assert(optee_vectors);
93*aa5da461SJens Wiklander 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
94*aa5da461SJens Wiklander 
95*aa5da461SJens Wiklander 	/* Program the entry point, power_state parameter and enter OPTEE */
96*aa5da461SJens Wiklander 	write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
97*aa5da461SJens Wiklander 		      CTX_GPREG_X0,
98*aa5da461SJens Wiklander 		      power_state);
99*aa5da461SJens Wiklander 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_suspend_entry);
100*aa5da461SJens Wiklander 	rc = opteed_synchronous_sp_entry(optee_ctx);
101*aa5da461SJens Wiklander 
102*aa5da461SJens Wiklander 	/*
103*aa5da461SJens Wiklander 	 * Read the response from OPTEE. A non-zero return means that
104*aa5da461SJens Wiklander 	 * something went wrong while communicating with OPTEE.
105*aa5da461SJens Wiklander 	 */
106*aa5da461SJens Wiklander 	if (rc != 0)
107*aa5da461SJens Wiklander 		panic();
108*aa5da461SJens Wiklander 
109*aa5da461SJens Wiklander 	/* Update its context to reflect the state OPTEE is in */
110*aa5da461SJens Wiklander 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND);
111*aa5da461SJens Wiklander }
112*aa5da461SJens Wiklander 
113*aa5da461SJens Wiklander /*******************************************************************************
114*aa5da461SJens Wiklander  * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits
115*aa5da461SJens Wiklander  * before passing control back to the Secure Monitor. Entry in S-El1 is done
116*aa5da461SJens Wiklander  * after initialising minimal architectural state that guarantees safe
117*aa5da461SJens Wiklander  * execution.
118*aa5da461SJens Wiklander  ******************************************************************************/
119*aa5da461SJens Wiklander static void opteed_cpu_on_finish_handler(uint64_t cookie)
120*aa5da461SJens Wiklander {
121*aa5da461SJens Wiklander 	int32_t rc = 0;
122*aa5da461SJens Wiklander 	uint64_t mpidr = read_mpidr();
123*aa5da461SJens Wiklander 	uint32_t linear_id = platform_get_core_pos(mpidr);
124*aa5da461SJens Wiklander 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
125*aa5da461SJens Wiklander 	entry_point_info_t optee_on_entrypoint;
126*aa5da461SJens Wiklander 
127*aa5da461SJens Wiklander 	assert(optee_vectors);
128*aa5da461SJens Wiklander 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF);
129*aa5da461SJens Wiklander 
130*aa5da461SJens Wiklander 	opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw,
131*aa5da461SJens Wiklander 				(uint64_t)&optee_vectors->cpu_on_entry,
132*aa5da461SJens Wiklander 				optee_ctx);
133*aa5da461SJens Wiklander 
134*aa5da461SJens Wiklander 	/* Initialise this cpu's secure context */
135*aa5da461SJens Wiklander 	cm_init_context(mpidr, &optee_on_entrypoint);
136*aa5da461SJens Wiklander 
137*aa5da461SJens Wiklander 	/* Enter OPTEE */
138*aa5da461SJens Wiklander 	rc = opteed_synchronous_sp_entry(optee_ctx);
139*aa5da461SJens Wiklander 
140*aa5da461SJens Wiklander 	/*
141*aa5da461SJens Wiklander 	 * Read the response from OPTEE. A non-zero return means that
142*aa5da461SJens Wiklander 	 * something went wrong while communicating with OPTEE.
143*aa5da461SJens Wiklander 	 */
144*aa5da461SJens Wiklander 	if (rc != 0)
145*aa5da461SJens Wiklander 		panic();
146*aa5da461SJens Wiklander 
147*aa5da461SJens Wiklander 	/* Update its context to reflect the state OPTEE is in */
148*aa5da461SJens Wiklander 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
149*aa5da461SJens Wiklander }
150*aa5da461SJens Wiklander 
151*aa5da461SJens Wiklander /*******************************************************************************
152*aa5da461SJens Wiklander  * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it
153*aa5da461SJens Wiklander  * completed the preceding suspend call. Use that context to program an entry
154*aa5da461SJens Wiklander  * into OPTEE to allow it to do any remaining book keeping
155*aa5da461SJens Wiklander  ******************************************************************************/
156*aa5da461SJens Wiklander static void opteed_cpu_suspend_finish_handler(uint64_t suspend_level)
157*aa5da461SJens Wiklander {
158*aa5da461SJens Wiklander 	int32_t rc = 0;
159*aa5da461SJens Wiklander 	uint64_t mpidr = read_mpidr();
160*aa5da461SJens Wiklander 	uint32_t linear_id = platform_get_core_pos(mpidr);
161*aa5da461SJens Wiklander 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
162*aa5da461SJens Wiklander 
163*aa5da461SJens Wiklander 	assert(optee_vectors);
164*aa5da461SJens Wiklander 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND);
165*aa5da461SJens Wiklander 
166*aa5da461SJens Wiklander 	/* Program the entry point, suspend_level and enter the SP */
167*aa5da461SJens Wiklander 	write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
168*aa5da461SJens Wiklander 		      CTX_GPREG_X0,
169*aa5da461SJens Wiklander 		      suspend_level);
170*aa5da461SJens Wiklander 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_resume_entry);
171*aa5da461SJens Wiklander 	rc = opteed_synchronous_sp_entry(optee_ctx);
172*aa5da461SJens Wiklander 
173*aa5da461SJens Wiklander 	/*
174*aa5da461SJens Wiklander 	 * Read the response from OPTEE. A non-zero return means that
175*aa5da461SJens Wiklander 	 * something went wrong while communicating with OPTEE.
176*aa5da461SJens Wiklander 	 */
177*aa5da461SJens Wiklander 	if (rc != 0)
178*aa5da461SJens Wiklander 		panic();
179*aa5da461SJens Wiklander 
180*aa5da461SJens Wiklander 	/* Update its context to reflect the state OPTEE is in */
181*aa5da461SJens Wiklander 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
182*aa5da461SJens Wiklander }
183*aa5da461SJens Wiklander 
184*aa5da461SJens Wiklander /*******************************************************************************
185*aa5da461SJens Wiklander  * Return the type of OPTEE the OPTEED is dealing with. Report the current
186*aa5da461SJens Wiklander  * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
187*aa5da461SJens Wiklander  ******************************************************************************/
188*aa5da461SJens Wiklander static int32_t opteed_cpu_migrate_info(uint64_t *resident_cpu)
189*aa5da461SJens Wiklander {
190*aa5da461SJens Wiklander 	return OPTEE_MIGRATE_INFO;
191*aa5da461SJens Wiklander }
192*aa5da461SJens Wiklander 
193*aa5da461SJens Wiklander /*******************************************************************************
194*aa5da461SJens Wiklander  * System is about to be switched off. Allow the OPTEED/OPTEE to perform
195*aa5da461SJens Wiklander  * any actions needed.
196*aa5da461SJens Wiklander  ******************************************************************************/
197*aa5da461SJens Wiklander static void opteed_system_off(void)
198*aa5da461SJens Wiklander {
199*aa5da461SJens Wiklander 	uint64_t mpidr = read_mpidr();
200*aa5da461SJens Wiklander 	uint32_t linear_id = platform_get_core_pos(mpidr);
201*aa5da461SJens Wiklander 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
202*aa5da461SJens Wiklander 
203*aa5da461SJens Wiklander 	assert(optee_vectors);
204*aa5da461SJens Wiklander 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
205*aa5da461SJens Wiklander 
206*aa5da461SJens Wiklander 	/* Program the entry point */
207*aa5da461SJens Wiklander 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_off_entry);
208*aa5da461SJens Wiklander 
209*aa5da461SJens Wiklander 	/* Enter OPTEE. We do not care about the return value because we
210*aa5da461SJens Wiklander 	 * must continue the shutdown anyway */
211*aa5da461SJens Wiklander 	opteed_synchronous_sp_entry(optee_ctx);
212*aa5da461SJens Wiklander }
213*aa5da461SJens Wiklander 
214*aa5da461SJens Wiklander /*******************************************************************************
215*aa5da461SJens Wiklander  * System is about to be reset. Allow the OPTEED/OPTEE to perform
216*aa5da461SJens Wiklander  * any actions needed.
217*aa5da461SJens Wiklander  ******************************************************************************/
218*aa5da461SJens Wiklander static void opteed_system_reset(void)
219*aa5da461SJens Wiklander {
220*aa5da461SJens Wiklander 	uint64_t mpidr = read_mpidr();
221*aa5da461SJens Wiklander 	uint32_t linear_id = platform_get_core_pos(mpidr);
222*aa5da461SJens Wiklander 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
223*aa5da461SJens Wiklander 
224*aa5da461SJens Wiklander 	assert(optee_vectors);
225*aa5da461SJens Wiklander 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
226*aa5da461SJens Wiklander 
227*aa5da461SJens Wiklander 	/* Program the entry point */
228*aa5da461SJens Wiklander 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->system_reset_entry);
229*aa5da461SJens Wiklander 
230*aa5da461SJens Wiklander 	/* Enter OPTEE. We do not care about the return value because we
231*aa5da461SJens Wiklander 	 * must continue the reset anyway */
232*aa5da461SJens Wiklander 	opteed_synchronous_sp_entry(optee_ctx);
233*aa5da461SJens Wiklander }
234*aa5da461SJens Wiklander 
235*aa5da461SJens Wiklander 
236*aa5da461SJens Wiklander /*******************************************************************************
237*aa5da461SJens Wiklander  * Structure populated by the OPTEE Dispatcher to be given a chance to
238*aa5da461SJens Wiklander  * perform any OPTEE bookkeeping before PSCI executes a power mgmt.
239*aa5da461SJens Wiklander  * operation.
240*aa5da461SJens Wiklander  ******************************************************************************/
241*aa5da461SJens Wiklander const spd_pm_ops_t opteed_pm = {
242*aa5da461SJens Wiklander 	.svc_on = opteed_cpu_on_handler,
243*aa5da461SJens Wiklander 	.svc_off = opteed_cpu_off_handler,
244*aa5da461SJens Wiklander 	.svc_suspend = opteed_cpu_suspend_handler,
245*aa5da461SJens Wiklander 	.svc_on_finish = opteed_cpu_on_finish_handler,
246*aa5da461SJens Wiklander 	.svc_suspend_finish = opteed_cpu_suspend_finish_handler,
247*aa5da461SJens Wiklander 	.svc_migrate = NULL,
248*aa5da461SJens Wiklander 	.svc_migrate_info = opteed_cpu_migrate_info,
249*aa5da461SJens Wiklander 	.svc_system_off = opteed_system_off,
250*aa5da461SJens Wiklander 	.svc_system_reset = opteed_system_reset,
251*aa5da461SJens Wiklander };
252*aa5da461SJens Wiklander 
253