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