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