blob: b5a6783323b4a748a47a0c511b286b35eb6059bd [file] [log] [blame]
Tejas Patel354fe572018-12-14 00:55:37 -08001/*
2 * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*
8 * Top-level SMC handler for Versal power management calls and
9 * IPI setup functions for communication with PMC.
10 */
11
12#include <errno.h>
13#include <plat_private.h>
Tejas Patel59c608a2019-01-09 04:10:29 -080014#include <stdbool.h>
15#include <common/runtime_svc.h>
16#include "pm_api_sys.h"
Tejas Patel354fe572018-12-14 00:55:37 -080017#include "pm_client.h"
18#include "pm_ipi.h"
19
Tejas Patel59c608a2019-01-09 04:10:29 -080020/* pm_up = true - UP, pm_up = false - DOWN */
21static bool pm_up;
22
Tejas Patel354fe572018-12-14 00:55:37 -080023/**
24 * pm_setup() - PM service setup
25 *
26 * @return On success, the initialization function must return 0.
27 * Any other return value will cause the framework to ignore
28 * the service
29 *
30 * Initialization functions for Versal power management for
31 * communicaton with PMC.
32 *
33 * Called from sip_svc_setup initialization function with the
34 * rt_svc_init signature.
35 */
36int pm_setup(void)
37{
38 int status, ret = 0;
39
40 status = pm_ipi_init(primary_proc);
41
42 if (status < 0) {
43 INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
44 ret = status;
Tejas Patel59c608a2019-01-09 04:10:29 -080045 } else {
46 pm_up = true;
Tejas Patel354fe572018-12-14 00:55:37 -080047 }
48
49 return ret;
50}
Tejas Patel59c608a2019-01-09 04:10:29 -080051
52/**
53 * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
54 * @smc_fid - Function Identifier
55 * @x1 - x4 - Arguments
56 * @cookie - Unused
57 * @handler - Pointer to caller's context structure
58 *
59 * @return - Unused
60 *
61 * Determines that smc_fid is valid and supported PM SMC Function ID from the
62 * list of pm_api_ids, otherwise completes the request with
63 * the unknown SMC Function ID
64 *
65 * The SMC calls for PM service are forwarded from SIP Service SMC handler
66 * function with rt_svc_handle signature
67 */
68uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
69 uint64_t x4, void *cookie, void *handle, uint64_t flags)
70{
71 enum pm_ret_status ret;
72
73 uint32_t pm_arg[4];
74
75 /* Handle case where PM wasn't initialized properly */
76 if (!pm_up)
77 SMC_RET1(handle, SMC_UNK);
78
79 pm_arg[0] = (uint32_t)x1;
80 pm_arg[1] = (uint32_t)(x1 >> 32);
81 pm_arg[2] = (uint32_t)x2;
82 pm_arg[3] = (uint32_t)(x2 >> 32);
83
84 switch (smc_fid & FUNCID_NUM_MASK) {
85 /* PM API Functions */
86 case PM_SELF_SUSPEND:
87 ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
88 pm_arg[3]);
89 SMC_RET1(handle, (uint64_t)ret);
90
Tejas Patel6b282252019-01-10 03:03:47 -080091 case PM_FORCE_POWERDOWN:
92 ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
93 SMC_RET1(handle, (uint64_t)ret);
94
Tejas Patel59c608a2019-01-09 04:10:29 -080095 case PM_REQ_SUSPEND:
96 ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
97 pm_arg[3]);
98 SMC_RET1(handle, (uint64_t)ret);
99
100 case PM_ABORT_SUSPEND:
101 ret = pm_abort_suspend(pm_arg[0]);
102 SMC_RET1(handle, (uint64_t)ret);
103
Tejas Patel6b282252019-01-10 03:03:47 -0800104 case PM_SYSTEM_SHUTDOWN:
105 ret = pm_system_shutdown(pm_arg[0], pm_arg[1]);
106 SMC_RET1(handle, (uint64_t)ret);
107
Tejas Patel49cd8712019-01-23 14:18:51 +0530108 case PM_REQ_WAKEUP:
109 ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
110 SMC_RET1(handle, (uint64_t)ret);
111
Tejas Pateldb812052019-01-23 14:18:53 +0530112 case PM_SET_WAKEUP_SOURCE:
113 ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
114 SMC_RET1(handle, (uint64_t)ret);
115
Tejas Patel59c608a2019-01-09 04:10:29 -0800116 case PM_REQUEST_DEVICE:
117 ret = pm_request_device(pm_arg[0], pm_arg[1], pm_arg[2],
118 pm_arg[3]);
119 SMC_RET1(handle, (uint64_t)ret);
120
121 case PM_RELEASE_DEVICE:
122 ret = pm_release_device(pm_arg[0]);
123 SMC_RET1(handle, (uint64_t)ret);
124
125 case PM_SET_REQUIREMENT:
126 ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
127 pm_arg[3]);
128 SMC_RET1(handle, (uint64_t)ret);
129
130 case PM_GET_API_VERSION:
131 {
132 uint32_t api_version;
133
134 ret = pm_get_api_version(&api_version);
135 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
136 ((uint64_t)api_version << 32));
137 }
138
139 case PM_GET_DEVICE_STATUS:
140 {
141 uint32_t buff[3];
142
143 ret = pm_get_device_status(pm_arg[0], buff);
144 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
145 (uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
146 }
147
148 case PM_RESET_ASSERT:
149 ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
150 SMC_RET1(handle, (uint64_t)ret);
151
152 case PM_RESET_GET_STATUS:
153 {
154 uint32_t reset_status;
155
156 ret = pm_reset_get_status(pm_arg[0], &reset_status);
157 SMC_RET1(handle, (uint64_t)ret |
158 ((uint64_t)reset_status << 32));
159 }
160
Tejas Patel02662022019-01-21 17:56:49 +0530161 case PM_INIT_FINALIZE:
162 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS);
163
Rajan Vaja649e9242019-03-04 11:09:40 +0530164 case PM_GET_CALLBACK_DATA:
165 {
166 uint32_t result[4] = {0};
167
168 pm_get_callbackdata(result, sizeof(result));
169 SMC_RET2(handle,
170 (uint64_t)result[0] | ((uint64_t)result[1] << 32),
171 (uint64_t)result[2] | ((uint64_t)result[3] << 32));
172 }
173
Tejas Patel59c608a2019-01-09 04:10:29 -0800174 case PM_PINCTRL_REQUEST:
175 ret = pm_pinctrl_request(pm_arg[0]);
176 SMC_RET1(handle, (uint64_t)ret);
177
178 case PM_PINCTRL_RELEASE:
179 ret = pm_pinctrl_release(pm_arg[0]);
180 SMC_RET1(handle, (uint64_t)ret);
181
182 case PM_PINCTRL_GET_FUNCTION:
183 {
184 uint32_t value = 0;
185
186 ret = pm_pinctrl_get_function(pm_arg[0], &value);
187 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
188 }
189
190 case PM_PINCTRL_SET_FUNCTION:
191 ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]);
192 SMC_RET1(handle, (uint64_t)ret);
193
194 case PM_PINCTRL_CONFIG_PARAM_GET:
195 {
196 uint32_t value;
197
198 ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value);
199 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
200 }
201
202 case PM_PINCTRL_CONFIG_PARAM_SET:
203 ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2]);
204 SMC_RET1(handle, (uint64_t)ret);
205
Tejas Patel9141f442019-01-10 03:03:48 -0800206 case PM_IOCTL:
207 {
208 uint32_t value;
209
210 ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
211 pm_arg[3], &value);
212 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
213 }
214
Tejas Patela3e34ad2019-02-01 17:25:19 +0530215 case PM_QUERY_DATA:
216 {
217 uint32_t data[4] = { 0 };
218
219 ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
220 pm_arg[3], data);
221 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32),
222 (uint64_t)data[1] | ((uint64_t)data[2] << 32));
223 }
224
Tejas Patel59c608a2019-01-09 04:10:29 -0800225 case PM_CLOCK_ENABLE:
226 ret = pm_clock_enable(pm_arg[0]);
227 SMC_RET1(handle, (uint64_t)ret);
228
229 case PM_CLOCK_DISABLE:
230 ret = pm_clock_disable(pm_arg[0]);
231 SMC_RET1(handle, (uint64_t)ret);
232
233 case PM_CLOCK_GETSTATE:
234 {
235 uint32_t value;
236
237 ret = pm_clock_get_state(pm_arg[0], &value);
238 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
239 }
240
241 case PM_CLOCK_SETDIVIDER:
242 ret = pm_clock_set_divider(pm_arg[0], pm_arg[1]);
243 SMC_RET1(handle, (uint64_t)ret);
244
245 case PM_CLOCK_GETDIVIDER:
246 {
247 uint32_t value;
248
249 ret = pm_clock_get_divider(pm_arg[0], &value);
250 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
251 }
252
253 case PM_CLOCK_SETPARENT:
254 ret = pm_clock_set_parent(pm_arg[0], pm_arg[1]);
255 SMC_RET1(handle, (uint64_t)ret);
256
257 case PM_CLOCK_GETPARENT:
258 {
259 uint32_t value;
260
261 ret = pm_clock_get_parent(pm_arg[0], &value);
262 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
263 }
264
265 case PM_PLL_SET_PARAMETER:
266 ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2]);
267 SMC_RET1(handle, (uint64_t)ret);
268
269 case PM_PLL_GET_PARAMETER:
270 {
271 uint32_t value;
272
273 ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value);
274 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
275 }
276
277 case PM_PLL_SET_MODE:
278 ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
279 SMC_RET1(handle, (uint64_t)ret);
280
281 case PM_PLL_GET_MODE:
282 {
283 uint32_t mode;
284
285 ret = pm_pll_get_mode(pm_arg[0], &mode);
286 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
287 }
288
Tejas Patel044001d2019-01-21 17:56:48 +0530289 case PM_GET_TRUSTZONE_VERSION:
290 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
291 ((uint64_t)VERSAL_TZ_VERSION << 32));
292
Ravi Patel22b0b492019-03-06 12:34:46 +0530293 case PM_FEATURE_CHECK:
294 {
295 uint32_t version;
296
297 ret = pm_feature_check(pm_arg[0], &version);
298 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)version << 32));
299 }
300
Tejas Patel59c608a2019-01-09 04:10:29 -0800301 default:
302 WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
303 SMC_RET1(handle, SMC_UNK);
304 }
305}