blob: 9e2f6c2a3765395dde042f0382c9844de596b0d7 [file] [log] [blame]
Achin Gupta607084e2014-02-09 18:24:19 +00001/*
2 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <stdio.h>
32#include <string.h>
33#include <assert.h>
34#include <arch_helpers.h>
35#include <console.h>
36#include <platform.h>
37#include <psci_private.h>
38#include <context_mgmt.h>
39#include <runtime_svc.h>
40#include <bl31.h>
41#include <bl32.h>
42#include <psci.h>
43#include <tspd_private.h>
44#include <debug.h>
45
46/*******************************************************************************
47 * The target cpu is being turned on. Allow the TSPD/TSP to perform any actions
48 * needed. Nothing at the moment.
49 ******************************************************************************/
50static void tspd_cpu_on_handler(uint64_t target_cpu)
51{
52}
53
54/*******************************************************************************
55 * This cpu is being turned off. Allow the TSPD/TSP to perform any actions
56 * needed
57 ******************************************************************************/
58static int32_t tspd_cpu_off_handler(uint64_t cookie)
59{
60 int32_t rc = 0;
61 uint64_t mpidr = read_mpidr();
62 uint32_t linear_id = platform_get_core_pos(mpidr);
63 tsp_context *tsp_ctx = &tspd_sp_context[linear_id];
64
65 assert(tsp_entry_info);
66 assert(tsp_ctx->state == TSP_STATE_ON);
67
68 /* Program the entry point and enter the TSP */
69 cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_off_entry);
70 rc = tspd_synchronous_sp_entry(tsp_ctx);
71
72 /*
73 * Read the response from the TSP. A non-zero return means that
74 * something went wrong while communicating with the TSP.
75 */
76 if (rc != 0)
77 panic();
78
79 /*
80 * Reset TSP's context for a fresh start when this cpu is turned on
81 * subsequently.
82 */
83 tsp_ctx->state = TSP_STATE_OFF;
84
85 return 0;
86}
87
88/*******************************************************************************
89 * This cpu is being suspended. S-EL1 state must have been saved in the
90 * resident cpu (mpidr format) if it is a UP/UP migratable TSP.
91 ******************************************************************************/
92static void tspd_cpu_suspend_handler(uint64_t power_state)
93{
94 int32_t rc = 0;
95 uint64_t mpidr = read_mpidr();
96 uint32_t linear_id = platform_get_core_pos(mpidr);
97 tsp_context *tsp_ctx = &tspd_sp_context[linear_id];
98
99 assert(tsp_entry_info);
100 assert(tsp_ctx->state == TSP_STATE_ON);
101
102 /* Program the entry point, power_state parameter and enter the TSP */
103 write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx),
104 CTX_GPREG_X0,
105 power_state);
106 cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_suspend_entry);
107 rc = tspd_synchronous_sp_entry(tsp_ctx);
108
109 /*
110 * Read the response from the TSP. A non-zero return means that
111 * something went wrong while communicating with the TSP.
112 */
113 if (rc != 0)
114 panic();
115
116 /* Update its context to reflect the state the TSP is in */
117 tsp_ctx->state = TSP_STATE_SUSPEND;
118}
119
120/*******************************************************************************
121 * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits
122 * before passing control back to the Secure Monitor. Entry in S-El1 is done
123 * after initialising minimal architectural state that guarantees safe
124 * execution.
125 ******************************************************************************/
126static void tspd_cpu_on_finish_handler(uint64_t cookie)
127{
128 int32_t rc = 0;
129 uint64_t mpidr = read_mpidr();
130 uint32_t linear_id = platform_get_core_pos(mpidr);
131 tsp_context *tsp_ctx = &tspd_sp_context[linear_id];
132
133 assert(tsp_entry_info);
134 assert(tsp_ctx->state == TSP_STATE_OFF);
135
136 /* Initialise this cpu's secure context */
137 tspd_init_secure_context((uint64_t) tsp_entry_info->cpu_on_entry,
138 TSP_AARCH64,
139 mpidr,
140 tsp_ctx);
141
142 /* Enter the TSP */
143 rc = tspd_synchronous_sp_entry(tsp_ctx);
144
145 /*
146 * Read the response from the TSP. A non-zero return means that
147 * something went wrong while communicating with the SP.
148 */
149 if (rc != 0)
150 panic();
151
152 /* Update its context to reflect the state the SP is in */
153 tsp_ctx->state = TSP_STATE_ON;
154}
155
156/*******************************************************************************
157 * This cpu has resumed from suspend. The SPD saved the TSP context when it
158 * completed the preceding suspend call. Use that context to program an entry
159 * into the TSP to allow it to do any remaining book keeping
160 ******************************************************************************/
161static void tspd_cpu_suspend_finish_handler(uint64_t suspend_level)
162{
163 int32_t rc = 0;
164 uint64_t mpidr = read_mpidr();
165 uint32_t linear_id = platform_get_core_pos(mpidr);
166 tsp_context *tsp_ctx = &tspd_sp_context[linear_id];
167
168 assert(tsp_entry_info);
169 assert(tsp_ctx->state == TSP_STATE_SUSPEND);
170
171 /* Program the entry point, suspend_level and enter the SP */
172 write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx),
173 CTX_GPREG_X0,
174 suspend_level);
175 cm_set_el3_elr(SECURE, (uint64_t) tsp_entry_info->cpu_resume_entry);
176 rc = tspd_synchronous_sp_entry(tsp_ctx);
177
178 /*
179 * Read the response from the TSP. A non-zero return means that
180 * something went wrong while communicating with the TSP.
181 */
182 if (rc != 0)
183 panic();
184
185 /* Update its context to reflect the state the SP is in */
186 tsp_ctx->state = TSP_STATE_ON;
187}
188
189/*******************************************************************************
190 * Return the type of TSP the TSPD is dealing with. Report the current resident
191 * cpu (mpidr format) if it is a UP/UP migratable TSP.
192 ******************************************************************************/
193static int32_t tspd_cpu_migrate_info(uint64_t *resident_cpu)
194{
195 return TSP_MIGRATE_INFO;
196}
197
198/*******************************************************************************
199 * Structure populated by the TSP Dispatcher to be given a chance to perform any
200 * TSP bookkeeping before PSCI executes a power mgmt. operation.
201 ******************************************************************************/
202const spd_pm_ops spd_pm = {
203 tspd_cpu_on_handler,
204 tspd_cpu_off_handler,
205 tspd_cpu_suspend_handler,
206 tspd_cpu_on_finish_handler,
207 tspd_cpu_suspend_finish_handler,
208 NULL,
209 tspd_cpu_migrate_info
210};
211