blob: 7f8e42fbad8a5d7de3e98eac2bca825be63db05b [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 Patel59c608a2019-01-09 04:10:29 -0800114 case PM_REQUEST_DEVICE:
115 ret = pm_request_device(pm_arg[0], pm_arg[1], pm_arg[2],
116 pm_arg[3]);
117 SMC_RET1(handle, (uint64_t)ret);
118
119 case PM_RELEASE_DEVICE:
120 ret = pm_release_device(pm_arg[0]);
121 SMC_RET1(handle, (uint64_t)ret);
122
123 case PM_SET_REQUIREMENT:
124 ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
125 pm_arg[3]);
126 SMC_RET1(handle, (uint64_t)ret);
127
128 case PM_GET_API_VERSION:
129 {
130 uint32_t api_version;
131
132 ret = pm_get_api_version(&api_version);
133 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
134 ((uint64_t)api_version << 32));
135 }
136
137 case PM_GET_DEVICE_STATUS:
138 {
139 uint32_t buff[3];
140
141 ret = pm_get_device_status(pm_arg[0], buff);
142 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
143 (uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
144 }
145
146 case PM_RESET_ASSERT:
147 ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
148 SMC_RET1(handle, (uint64_t)ret);
149
150 case PM_RESET_GET_STATUS:
151 {
152 uint32_t reset_status;
153
154 ret = pm_reset_get_status(pm_arg[0], &reset_status);
155 SMC_RET1(handle, (uint64_t)ret |
156 ((uint64_t)reset_status << 32));
157 }
158
Tejas Patel02662022019-01-21 17:56:49 +0530159 case PM_INIT_FINALIZE:
160 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS);
161
Tejas Patel59c608a2019-01-09 04:10:29 -0800162 case PM_PINCTRL_REQUEST:
163 ret = pm_pinctrl_request(pm_arg[0]);
164 SMC_RET1(handle, (uint64_t)ret);
165
166 case PM_PINCTRL_RELEASE:
167 ret = pm_pinctrl_release(pm_arg[0]);
168 SMC_RET1(handle, (uint64_t)ret);
169
170 case PM_PINCTRL_GET_FUNCTION:
171 {
172 uint32_t value = 0;
173
174 ret = pm_pinctrl_get_function(pm_arg[0], &value);
175 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
176 }
177
178 case PM_PINCTRL_SET_FUNCTION:
179 ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]);
180 SMC_RET1(handle, (uint64_t)ret);
181
182 case PM_PINCTRL_CONFIG_PARAM_GET:
183 {
184 uint32_t value;
185
186 ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value);
187 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
188 }
189
190 case PM_PINCTRL_CONFIG_PARAM_SET:
191 ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2]);
192 SMC_RET1(handle, (uint64_t)ret);
193
Tejas Patel9141f442019-01-10 03:03:48 -0800194 case PM_IOCTL:
195 {
196 uint32_t value;
197
198 ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
199 pm_arg[3], &value);
200 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
201 }
202
Tejas Patela3e34ad2019-02-01 17:25:19 +0530203 case PM_QUERY_DATA:
204 {
205 uint32_t data[4] = { 0 };
206
207 ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
208 pm_arg[3], data);
209 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32),
210 (uint64_t)data[1] | ((uint64_t)data[2] << 32));
211 }
212
Tejas Patel59c608a2019-01-09 04:10:29 -0800213 case PM_CLOCK_ENABLE:
214 ret = pm_clock_enable(pm_arg[0]);
215 SMC_RET1(handle, (uint64_t)ret);
216
217 case PM_CLOCK_DISABLE:
218 ret = pm_clock_disable(pm_arg[0]);
219 SMC_RET1(handle, (uint64_t)ret);
220
221 case PM_CLOCK_GETSTATE:
222 {
223 uint32_t value;
224
225 ret = pm_clock_get_state(pm_arg[0], &value);
226 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
227 }
228
229 case PM_CLOCK_SETDIVIDER:
230 ret = pm_clock_set_divider(pm_arg[0], pm_arg[1]);
231 SMC_RET1(handle, (uint64_t)ret);
232
233 case PM_CLOCK_GETDIVIDER:
234 {
235 uint32_t value;
236
237 ret = pm_clock_get_divider(pm_arg[0], &value);
238 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
239 }
240
241 case PM_CLOCK_SETPARENT:
242 ret = pm_clock_set_parent(pm_arg[0], pm_arg[1]);
243 SMC_RET1(handle, (uint64_t)ret);
244
245 case PM_CLOCK_GETPARENT:
246 {
247 uint32_t value;
248
249 ret = pm_clock_get_parent(pm_arg[0], &value);
250 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
251 }
252
253 case PM_PLL_SET_PARAMETER:
254 ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2]);
255 SMC_RET1(handle, (uint64_t)ret);
256
257 case PM_PLL_GET_PARAMETER:
258 {
259 uint32_t value;
260
261 ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value);
262 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
263 }
264
265 case PM_PLL_SET_MODE:
266 ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
267 SMC_RET1(handle, (uint64_t)ret);
268
269 case PM_PLL_GET_MODE:
270 {
271 uint32_t mode;
272
273 ret = pm_pll_get_mode(pm_arg[0], &mode);
274 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
275 }
276
Tejas Patel044001d2019-01-21 17:56:48 +0530277 case PM_GET_TRUSTZONE_VERSION:
278 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
279 ((uint64_t)VERSAL_TZ_VERSION << 32));
280
Tejas Patel59c608a2019-01-09 04:10:29 -0800281 default:
282 WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
283 SMC_RET1(handle, SMC_UNK);
284 }
285}