blob: 8ac9a1d0dc1f60cdeac6d6e29aedecc2a508d938 [file] [log] [blame]
Tejas Patel9d09ff92019-01-08 01:46:35 -08001/*
2 * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7/*
8 * Versal system level PM-API functions and communication with PMC via
9 * IPI interrupts
10 */
11
12#include <pm_common.h>
13#include <pm_ipi.h>
Tejas Patelfe0e10a2019-12-08 23:29:44 -080014#include <plat/common/platform.h>
Tejas Patel9d09ff92019-01-08 01:46:35 -080015#include "pm_api_sys.h"
16#include "pm_client.h"
17
18/*********************************************************************
19 * Target module IDs macros
20 ********************************************************************/
21#define LIBPM_MODULE_ID 0x2
22#define LOADER_MODULE_ID 0x7
23
24/**
25 * Assigning of argument values into array elements.
26 */
27#define PM_PACK_PAYLOAD1(pl, mid, arg0) { \
28 pl[0] = (uint32_t)((uint32_t)((arg0) & 0xFF) | (mid << 8)); \
29}
30
Tejas Patelfe0e10a2019-12-08 23:29:44 -080031#define PM_PACK_PAYLOAD2(pl, mid, arg0, arg1) { \
32 pl[1] = (uint32_t)(arg1); \
33 PM_PACK_PAYLOAD1(pl, mid, arg0); \
34}
35
36#define PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2) { \
37 pl[2] = (uint32_t)(arg2); \
38 PM_PACK_PAYLOAD2(pl, mid, arg0, arg1); \
39}
40
41#define PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3) { \
42 pl[3] = (uint32_t)(arg3); \
43 PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2); \
44}
45
46#define PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4) { \
47 pl[4] = (uint32_t)(arg4); \
48 PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3); \
49}
50
51#define PM_PACK_PAYLOAD6(pl, mid, arg0, arg1, arg2, arg3, arg4, arg5) { \
52 pl[5] = (uint32_t)(arg5); \
53 PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4); \
54}
55
Tejas Patel9d09ff92019-01-08 01:46:35 -080056/* PM API functions */
57
58/**
59 * pm_get_api_version() - Get version number of PMC PM firmware
60 * @version Returns 32-bit version number of PMC Power Management Firmware
61 *
62 * @return Returns status, either success or error+reason
63 */
64enum pm_ret_status pm_get_api_version(unsigned int *version)
65{
66 uint32_t payload[PAYLOAD_ARG_CNT];
67
68 /* Send request to the PMC */
69 PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_API_VERSION);
70 return pm_ipi_send_sync(primary_proc, payload, version, 1);
71}
Tejas Patelfe0e10a2019-12-08 23:29:44 -080072
73/**
74 * pm_self_suspend() - PM call for processor to suspend itself
75 * @nid Node id of the processor or subsystem
76 * @latency Requested maximum wakeup latency (not supported)
77 * @state Requested state
78 * @address Resume address
79 *
80 * This is a blocking call, it will return only once PMU has responded.
81 * On a wakeup, resume address will be automatically set by PMU.
82 *
83 * @return Returns status, either success or error+reason
84 */
85enum pm_ret_status pm_self_suspend(uint32_t nid,
86 unsigned int latency,
87 unsigned int state,
88 uintptr_t address)
89{
90 uint32_t payload[PAYLOAD_ARG_CNT];
91 unsigned int cpuid = plat_my_core_pos();
92 const struct pm_proc *proc = pm_get_proc(cpuid);
93
94 if (!proc) {
95 WARN("Failed to get proc %d\n", cpuid);
96 return PM_RET_ERROR_INTERNAL;
97 }
98
99 /*
100 * Do client specific suspend operations
101 * (e.g. set powerdown request bit)
102 */
103 pm_client_suspend(proc, state);
104
105 /* Send request to the PLM */
106 PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, PM_SELF_SUSPEND,
107 proc->node_id, latency, state, address,
108 (address >> 32));
109 return pm_ipi_send_sync(proc, payload, NULL, 0);
110}
111
112/**
113 * pm_abort_suspend() - PM call to announce that a prior suspend request
114 * is to be aborted.
115 * @reason Reason for the abort
116 *
117 * Calling PU expects the PMU to abort the initiated suspend procedure.
118 * This is a non-blocking call without any acknowledge.
119 *
120 * @return Returns status, either success or error+reason
121 */
122enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
123{
124 uint32_t payload[PAYLOAD_ARG_CNT];
125
126 /*
127 * Do client specific abort suspend operations
128 * (e.g. enable interrupts and clear powerdown request bit)
129 */
130 pm_client_abort_suspend();
131
132 /* Send request to the PLM */
133 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_ABORT_SUSPEND, reason,
134 primary_proc->node_id);
135 return pm_ipi_send(primary_proc, payload);
136}
137
138/**
139 * pm_req_suspend() - PM call to request for another PU or subsystem to
140 * be suspended gracefully.
141 * @target Node id of the targeted PU or subsystem
142 * @ack Flag to specify whether acknowledge is requested
143 * @latency Requested wakeup latency (not supported)
144 * @state Requested state (not supported)
145 *
146 * @return Returns status, either success or error+reason
147 */
148enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack,
149 unsigned int latency, unsigned int state)
150{
151 uint32_t payload[PAYLOAD_ARG_CNT];
152
153 /* Send request to the PMU */
154 PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_REQ_SUSPEND, target,
155 latency, state);
156 if (ack == IPI_BLOCKING)
157 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
158 else
159 return pm_ipi_send(primary_proc, payload);
160}
Tejas Patel41f3e0b2019-01-08 01:46:37 -0800161
162/**
163 * pm_request_device() - Request a device
164 * @device_id Device ID
165 * @capabilities Requested capabilities for the device
166 * @qos Required Quality of Service
167 * @ack Flag to specify whether acknowledge requested
168 *
169 * @return Returns status, either success or error+reason
170 */
171enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
172 uint32_t qos, uint32_t ack)
173{
174 uint32_t payload[PAYLOAD_ARG_CNT];
175
176 /* Send request to the PMC */
177 PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQUEST_DEVICE,
178 device_id, capabilities, qos, ack);
179
180 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
181}
182
183/**
184 * pm_release_device() - Release a device
185 * @device_id Device ID
186 *
187 * @return Returns status, either success or error+reason
188 */
189enum pm_ret_status pm_release_device(uint32_t device_id)
190{
191 uint32_t payload[PAYLOAD_ARG_CNT];
192
193 /* Send request to the PMC */
194 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RELEASE_DEVICE,
195 device_id);
196
197 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
198}
199
200/**
201 * pm_set_requirement() - Set requirement for the device
202 * @device_id Device ID
203 * @capabilities Requested capabilities for the device
204 * @latency Requested maximum latency
205 * @qos Required Quality of Service
206 *
207 * @return Returns status, either success or error+reason
208 */
209enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
210 uint32_t latency, uint32_t qos)
211{
212 uint32_t payload[PAYLOAD_ARG_CNT];
213
214 /* Send request to the PMC */
215 PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_SET_REQUIREMENT,
216 device_id, capabilities, latency, qos);
217
218 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
219}
220
221/**
222 * pm_get_device_status() - Get device's status
223 * @device_id Device ID
224 * @response Buffer to store device status response
225 *
226 * @return Returns status, either success or error+reason
227 */
228enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response)
229{
230 uint32_t payload[PAYLOAD_ARG_CNT];
231
232 /* Send request to the PMC */
233 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_GET_DEVICE_STATUS,
234 device_id);
235
236 return pm_ipi_send_sync(primary_proc, payload, response, 3);
237}
Tejas Patel87c4f3a2019-01-08 01:46:38 -0800238
239/**
240 * pm_reset_assert() - Assert/De-assert reset
241 * @reset Reset ID
242 * @assert Assert (1) or de-assert (0)
243 *
244 * @return Returns status, either success or error+reason
245 */
246enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert)
247{
248 uint32_t payload[PAYLOAD_ARG_CNT];
249
250 /* Send request to the PMC */
251 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset,
252 assert);
253
254 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
255}
256
257/**
258 * pm_reset_get_status() - Get current status of a reset line
259 * @reset Reset ID
260 * @status Returns current status of selected reset ID
261 *
262 * @return Returns status, either success or error+reason
263 */
264enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status)
265{
266 uint32_t payload[PAYLOAD_ARG_CNT];
267
268 /* Send request to the PMC */
269 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset);
270
271 return pm_ipi_send_sync(primary_proc, payload, status, 1);
272}
Tejas Patel20e92022019-01-08 01:46:39 -0800273
274/**
275 * pm_pinctrl_request() - Request a pin
276 * @pin Pin ID
277 *
278 * @return Returns status, either success or error+reason
279 */
280enum pm_ret_status pm_pinctrl_request(uint32_t pin)
281{
282 uint32_t payload[PAYLOAD_ARG_CNT];
283
284 /* Send request to the PMC */
285 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_REQUEST, pin);
286
287 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
288}
289
290/**
291 * pm_pinctrl_release() - Release a pin
292 * @pin Pin ID
293 *
294 * @return Returns status, either success or error+reason
295 */
296enum pm_ret_status pm_pinctrl_release(uint32_t pin)
297{
298 uint32_t payload[PAYLOAD_ARG_CNT];
299
300 /* Send request to the PMC */
301 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_RELEASE, pin);
302
303 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
304}
305
306/**
307 * pm_pinctrl_set_function() - Set pin function
308 * @pin Pin ID
309 * @function Function ID
310 *
311 * @return Returns status, either success or error+reason
312 */
313enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function)
314{
315 uint32_t payload[PAYLOAD_ARG_CNT];
316
317 /* Send request to the PMC */
318 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION, pin,
319 function)
320
321 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
322}
323
324/**
325 * pm_pinctrl_get_function() - Get function set on the pin
326 * @pin Pin ID
327 * @function Function set on the pin
328 *
329 * @return Returns status, either success or error+reason
330 */
331enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function)
332{
333 uint32_t payload[PAYLOAD_ARG_CNT];
334
335 /* Send request to the PMC */
336 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION,
337 pin);
338
339 return pm_ipi_send_sync(primary_proc, payload, function, 1);
340}
341
342/**
343 * pm_pinctrl_set_pin_param() - Set configuration parameter for the pin
344 * @pin Pin ID
345 * @param Parameter ID
346 * @value Parameter value
347 *
348 * @return Returns status, either success or error+reason
349 */
350enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
351 uint32_t value)
352{
353 uint32_t payload[PAYLOAD_ARG_CNT];
354
355 /* Send request to the PMC */
356 PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_SET,
357 pin, param, value);
358
359 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
360}
361
362/**
363 * pm_pinctrl_get_pin_param() - Get configuration parameter value for the pin
364 * @pin Pin ID
365 * @param Parameter ID
366 * @value Buffer to store parameter value
367 *
368 * @return Returns status, either success or error+reason
369 */
370enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
371 uint32_t *value)
372{
373 uint32_t payload[PAYLOAD_ARG_CNT];
374
375 /* Send request to the PMC */
376 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_GET,
377 pin, param);
378
379 return pm_ipi_send_sync(primary_proc, payload, value, 1);
380}
Tejas Patel1f56fb12019-01-08 01:46:40 -0800381
382/**
383 * pm_clock_enable() - Enable the clock
384 * @clk_id Clock ID
385 *
386 * @return Returns status, either success or error+reason
387 */
388enum pm_ret_status pm_clock_enable(uint32_t clk_id)
389{
390 uint32_t payload[PAYLOAD_ARG_CNT];
391
392 /* Send request to the PMC */
393 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_ENABLE, clk_id);
394
395 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
396}
397
398/**
399 * pm_clock_disable() - Disable the clock
400 * @clk_id Clock ID
401 *
402 * @return Returns status, either success or error+reason
403 */
404enum pm_ret_status pm_clock_disable(uint32_t clk_id)
405{
406 uint32_t payload[PAYLOAD_ARG_CNT];
407
408 /* Send request to the PMC */
409 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_DISABLE, clk_id);
410
411 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
412}
413
414/**
415 * pm_clock_get_state() - Get clock status
416 * @clk_id Clock ID
417 * @state: Buffer to store clock status (1: Enabled, 0:Disabled)
418 *
419 * @return Returns status, either success or error+reason
420 */
421enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state)
422{
423 uint32_t payload[PAYLOAD_ARG_CNT];
424
425 /* Send request to the PMC */
426 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETSTATE, clk_id);
427
428 return pm_ipi_send_sync(primary_proc, payload, state, 1);
429}
430
431/**
432 * pm_clock_set_divider() - Set divider for the clock
433 * @clk_id Clock ID
434 * @divider Divider value
435 *
436 * @return Returns status, either success or error+reason
437 */
438enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider)
439{
440 uint32_t payload[PAYLOAD_ARG_CNT];
441
442 /* Send request to the PMC */
443 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETDIVIDER, clk_id,
444 divider);
445
446 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
447}
448
449/**
450 * pm_clock_get_divider() - Get divider value for the clock
451 * @clk_id Clock ID
452 * @divider: Buffer to store clock divider value
453 *
454 * @return Returns status, either success or error+reason
455 */
456enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider)
457{
458 uint32_t payload[PAYLOAD_ARG_CNT];
459
460 /* Send request to the PMC */
461 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETDIVIDER, clk_id);
462
463 return pm_ipi_send_sync(primary_proc, payload, divider, 1);
464}
465
466/**
467 * pm_clock_set_parent() - Set parent for the clock
468 * @clk_id Clock ID
469 * @parent Parent ID
470 *
471 * @return Returns status, either success or error+reason
472 */
473enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent)
474{
475 uint32_t payload[PAYLOAD_ARG_CNT];
476
477 /* Send request to the PMC */
478 PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETPARENT, clk_id,
479 parent);
480
481 return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
482}
483
484/**
485 * pm_clock_get_parent() - Get parent value for the clock
486 * @clk_id Clock ID
487 * @parent: Buffer to store clock parent value
488 *
489 * @return Returns status, either success or error+reason
490 */
491enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent)
492{
493 uint32_t payload[PAYLOAD_ARG_CNT];
494
495 /* Send request to the PMC */
496 PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETPARENT, clk_id);
497
498 return pm_ipi_send_sync(primary_proc, payload, parent, 1);
499}