blob: 5dd315799295175d11a874bf82d04eaecb59feef [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
91 case PM_REQ_SUSPEND:
92 ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
93 pm_arg[3]);
94 SMC_RET1(handle, (uint64_t)ret);
95
96 case PM_ABORT_SUSPEND:
97 ret = pm_abort_suspend(pm_arg[0]);
98 SMC_RET1(handle, (uint64_t)ret);
99
100 case PM_REQUEST_DEVICE:
101 ret = pm_request_device(pm_arg[0], pm_arg[1], pm_arg[2],
102 pm_arg[3]);
103 SMC_RET1(handle, (uint64_t)ret);
104
105 case PM_RELEASE_DEVICE:
106 ret = pm_release_device(pm_arg[0]);
107 SMC_RET1(handle, (uint64_t)ret);
108
109 case PM_SET_REQUIREMENT:
110 ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
111 pm_arg[3]);
112 SMC_RET1(handle, (uint64_t)ret);
113
114 case PM_GET_API_VERSION:
115 {
116 uint32_t api_version;
117
118 ret = pm_get_api_version(&api_version);
119 SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
120 ((uint64_t)api_version << 32));
121 }
122
123 case PM_GET_DEVICE_STATUS:
124 {
125 uint32_t buff[3];
126
127 ret = pm_get_device_status(pm_arg[0], buff);
128 SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
129 (uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
130 }
131
132 case PM_RESET_ASSERT:
133 ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
134 SMC_RET1(handle, (uint64_t)ret);
135
136 case PM_RESET_GET_STATUS:
137 {
138 uint32_t reset_status;
139
140 ret = pm_reset_get_status(pm_arg[0], &reset_status);
141 SMC_RET1(handle, (uint64_t)ret |
142 ((uint64_t)reset_status << 32));
143 }
144
145 case PM_PINCTRL_REQUEST:
146 ret = pm_pinctrl_request(pm_arg[0]);
147 SMC_RET1(handle, (uint64_t)ret);
148
149 case PM_PINCTRL_RELEASE:
150 ret = pm_pinctrl_release(pm_arg[0]);
151 SMC_RET1(handle, (uint64_t)ret);
152
153 case PM_PINCTRL_GET_FUNCTION:
154 {
155 uint32_t value = 0;
156
157 ret = pm_pinctrl_get_function(pm_arg[0], &value);
158 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
159 }
160
161 case PM_PINCTRL_SET_FUNCTION:
162 ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]);
163 SMC_RET1(handle, (uint64_t)ret);
164
165 case PM_PINCTRL_CONFIG_PARAM_GET:
166 {
167 uint32_t value;
168
169 ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value);
170 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
171 }
172
173 case PM_PINCTRL_CONFIG_PARAM_SET:
174 ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2]);
175 SMC_RET1(handle, (uint64_t)ret);
176
177 case PM_CLOCK_ENABLE:
178 ret = pm_clock_enable(pm_arg[0]);
179 SMC_RET1(handle, (uint64_t)ret);
180
181 case PM_CLOCK_DISABLE:
182 ret = pm_clock_disable(pm_arg[0]);
183 SMC_RET1(handle, (uint64_t)ret);
184
185 case PM_CLOCK_GETSTATE:
186 {
187 uint32_t value;
188
189 ret = pm_clock_get_state(pm_arg[0], &value);
190 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
191 }
192
193 case PM_CLOCK_SETDIVIDER:
194 ret = pm_clock_set_divider(pm_arg[0], pm_arg[1]);
195 SMC_RET1(handle, (uint64_t)ret);
196
197 case PM_CLOCK_GETDIVIDER:
198 {
199 uint32_t value;
200
201 ret = pm_clock_get_divider(pm_arg[0], &value);
202 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
203 }
204
205 case PM_CLOCK_SETPARENT:
206 ret = pm_clock_set_parent(pm_arg[0], pm_arg[1]);
207 SMC_RET1(handle, (uint64_t)ret);
208
209 case PM_CLOCK_GETPARENT:
210 {
211 uint32_t value;
212
213 ret = pm_clock_get_parent(pm_arg[0], &value);
214 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
215 }
216
217 case PM_PLL_SET_PARAMETER:
218 ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2]);
219 SMC_RET1(handle, (uint64_t)ret);
220
221 case PM_PLL_GET_PARAMETER:
222 {
223 uint32_t value;
224
225 ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value);
226 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
227 }
228
229 case PM_PLL_SET_MODE:
230 ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
231 SMC_RET1(handle, (uint64_t)ret);
232
233 case PM_PLL_GET_MODE:
234 {
235 uint32_t mode;
236
237 ret = pm_pll_get_mode(pm_arg[0], &mode);
238 SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
239 }
240
241 default:
242 WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
243 SMC_RET1(handle, SMC_UNK);
244 }
245}