xref: /rk3399_ARM-atf/services/spd/opteed/opteed_pm.c (revision c3cf06f1a3a9b9ee8ac7a0ae505f95c45f7dca84)
1 /*
2  * Copyright (c) 2013-2017, 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 "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  ******************************************************************************/
19 static void opteed_cpu_on_handler(u_register_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  ******************************************************************************/
27 static int32_t opteed_cpu_off_handler(u_register_t unused)
28 {
29 	int32_t rc = 0;
30 	uint32_t linear_id = plat_my_core_pos();
31 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
32 
33 	assert(optee_vector_table);
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_vector_table->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  ******************************************************************************/
60 static void opteed_cpu_suspend_handler(u_register_t max_off_pwrlvl)
61 {
62 	int32_t rc = 0;
63 	uint32_t linear_id = plat_my_core_pos();
64 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
65 
66 	assert(optee_vector_table);
67 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
68 
69 	write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0,
70 		      max_off_pwrlvl);
71 
72 	/* Program the entry point and enter OPTEE */
73 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_suspend_entry);
74 	rc = opteed_synchronous_sp_entry(optee_ctx);
75 
76 	/*
77 	 * Read the response from OPTEE. A non-zero return means that
78 	 * something went wrong while communicating with OPTEE.
79 	 */
80 	if (rc != 0)
81 		panic();
82 
83 	/* Update its context to reflect the state OPTEE is in */
84 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND);
85 }
86 
87 /*******************************************************************************
88  * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits
89  * before passing control back to the Secure Monitor. Entry in S-El1 is done
90  * after initialising minimal architectural state that guarantees safe
91  * execution.
92  ******************************************************************************/
93 static void opteed_cpu_on_finish_handler(u_register_t unused)
94 {
95 	int32_t rc = 0;
96 	uint32_t linear_id = plat_my_core_pos();
97 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
98 	entry_point_info_t optee_on_entrypoint;
99 
100 	assert(optee_vector_table);
101 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF);
102 
103 	opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw,
104 				(uint64_t)&optee_vector_table->cpu_on_entry,
105 				0, 0, 0, optee_ctx);
106 
107 	/* Initialise this cpu's secure context */
108 	cm_init_my_context(&optee_on_entrypoint);
109 
110 	/* Enter OPTEE */
111 	rc = opteed_synchronous_sp_entry(optee_ctx);
112 
113 	/*
114 	 * Read the response from OPTEE. A non-zero return means that
115 	 * something went wrong while communicating with OPTEE.
116 	 */
117 	if (rc != 0)
118 		panic();
119 
120 	/* Update its context to reflect the state OPTEE is in */
121 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
122 }
123 
124 /*******************************************************************************
125  * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it
126  * completed the preceding suspend call. Use that context to program an entry
127  * into OPTEE to allow it to do any remaining book keeping
128  ******************************************************************************/
129 static void opteed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl)
130 {
131 	int32_t rc = 0;
132 	uint32_t linear_id = plat_my_core_pos();
133 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
134 
135 	assert(optee_vector_table);
136 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND);
137 
138 	/* Program the entry point, max_off_pwrlvl and enter the SP */
139 	write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx),
140 		      CTX_GPREG_X0,
141 		      max_off_pwrlvl);
142 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_resume_entry);
143 	rc = opteed_synchronous_sp_entry(optee_ctx);
144 
145 	/*
146 	 * Read the response from OPTEE. A non-zero return means that
147 	 * something went wrong while communicating with OPTEE.
148 	 */
149 	if (rc != 0)
150 		panic();
151 
152 	/* Update its context to reflect the state OPTEE is in */
153 	set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);
154 }
155 
156 /*******************************************************************************
157  * Return the type of OPTEE the OPTEED is dealing with. Report the current
158  * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE.
159  ******************************************************************************/
160 static int32_t opteed_cpu_migrate_info(u_register_t *resident_cpu)
161 {
162 	return OPTEE_MIGRATE_INFO;
163 }
164 
165 /*******************************************************************************
166  * System is about to be switched off. Allow the OPTEED/OPTEE to perform
167  * any actions needed.
168  ******************************************************************************/
169 static void opteed_system_off(void)
170 {
171 	uint32_t linear_id = plat_my_core_pos();
172 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
173 
174 	assert(optee_vector_table);
175 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
176 
177 	/* Program the entry point */
178 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_off_entry);
179 
180 	/* Enter OPTEE. We do not care about the return value because we
181 	 * must continue the shutdown anyway */
182 	opteed_synchronous_sp_entry(optee_ctx);
183 }
184 
185 /*******************************************************************************
186  * System is about to be reset. Allow the OPTEED/OPTEE to perform
187  * any actions needed.
188  ******************************************************************************/
189 static void opteed_system_reset(void)
190 {
191 	uint32_t linear_id = plat_my_core_pos();
192 	optee_context_t *optee_ctx = &opteed_sp_context[linear_id];
193 
194 	assert(optee_vector_table);
195 	assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON);
196 
197 	/* Program the entry point */
198 	cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_reset_entry);
199 
200 	/* Enter OPTEE. We do not care about the return value because we
201 	 * must continue the reset anyway */
202 	opteed_synchronous_sp_entry(optee_ctx);
203 }
204 
205 
206 /*******************************************************************************
207  * Structure populated by the OPTEE Dispatcher to be given a chance to
208  * perform any OPTEE bookkeeping before PSCI executes a power mgmt.
209  * operation.
210  ******************************************************************************/
211 const spd_pm_ops_t opteed_pm = {
212 	.svc_on = opteed_cpu_on_handler,
213 	.svc_off = opteed_cpu_off_handler,
214 	.svc_suspend = opteed_cpu_suspend_handler,
215 	.svc_on_finish = opteed_cpu_on_finish_handler,
216 	.svc_suspend_finish = opteed_cpu_suspend_finish_handler,
217 	.svc_migrate = NULL,
218 	.svc_migrate_info = opteed_cpu_migrate_info,
219 	.svc_system_off = opteed_system_off,
220 	.svc_system_reset = opteed_system_reset,
221 };
222