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