blob: 52d917111e40390858d63ef183bfdf57b7100a47 [file] [log] [blame]
Soren Brinkmann76fcae32016-03-06 20:16:27 -08001/*
2 * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * ZynqMP system level PM-API functions and communication with PMU via
33 * IPI interrupts
34 */
35
36#include <arch_helpers.h>
37#include <platform.h>
38#include "pm_client.h"
Filip Drazic46c0dc12016-05-12 16:17:31 +020039#include "pm_ipi.h"
Soren Brinkmann76fcae32016-03-06 20:16:27 -080040#include "pm_common.h"
41#include "pm_api_sys.h"
42
43/**
44 * Assigning of argument values into array elements.
45 */
46#define PM_PACK_PAYLOAD1(pl, arg0) { \
47 pl[0] = (uint32_t)(arg0); \
48}
49
50#define PM_PACK_PAYLOAD2(pl, arg0, arg1) { \
51 pl[1] = (uint32_t)(arg1); \
52 PM_PACK_PAYLOAD1(pl, arg0); \
53}
54
55#define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) { \
56 pl[2] = (uint32_t)(arg2); \
57 PM_PACK_PAYLOAD2(pl, arg0, arg1); \
58}
59
60#define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) { \
61 pl[3] = (uint32_t)(arg3); \
62 PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2); \
63}
64
65#define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) { \
66 pl[4] = (uint32_t)(arg4); \
67 PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3); \
68}
69
70#define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) { \
71 pl[5] = (uint32_t)(arg5); \
72 PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4); \
73}
74
75/**
76 * pm_self_suspend() - PM call for processor to suspend itself
77 * @nid Node id of the processor or subsystem
78 * @latency Requested maximum wakeup latency (not supported)
Filip Drazic0bd9d0c2016-07-20 17:17:39 +020079 * @state Requested state
Soren Brinkmann76fcae32016-03-06 20:16:27 -080080 * @address Resume address
81 *
82 * This is a blocking call, it will return only once PMU has responded.
83 * On a wakeup, resume address will be automatically set by PMU.
84 *
85 * @return Returns status, either success or error+reason
86 */
87enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
88 unsigned int latency,
89 unsigned int state,
90 uintptr_t address)
91{
92 uint32_t payload[PAYLOAD_ARG_CNT];
93 unsigned int cpuid = plat_my_core_pos();
94 const struct pm_proc *proc = pm_get_proc(cpuid);
95
96 /*
97 * Do client specific suspend operations
98 * (e.g. set powerdown request bit)
99 */
Filip Drazic4c0765a2016-07-26 12:11:33 +0200100 pm_client_suspend(proc, state);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800101 /* Send request to the PMU */
102 PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency,
103 state, address, (address >> 32));
104 return pm_ipi_send_sync(proc, payload, NULL);
105}
106
107/**
108 * pm_req_suspend() - PM call to request for another PU or subsystem to
109 * be suspended gracefully.
110 * @target Node id of the targeted PU or subsystem
111 * @ack Flag to specify whether acknowledge is requested
112 * @latency Requested wakeup latency (not supported)
113 * @state Requested state (not supported)
114 *
115 * @return Returns status, either success or error+reason
116 */
117enum pm_ret_status pm_req_suspend(enum pm_node_id target,
118 enum pm_request_ack ack,
119 unsigned int latency, unsigned int state)
120{
121 uint32_t payload[PAYLOAD_ARG_CNT];
122
123 /* Send request to the PMU */
124 PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state);
125 if (ack == REQ_ACK_BLOCKING)
126 return pm_ipi_send_sync(primary_proc, payload, NULL);
127 else
128 return pm_ipi_send(primary_proc, payload);
129}
130
131/**
132 * pm_req_wakeup() - PM call for processor to wake up selected processor
133 * or subsystem
134 * @target Node id of the processor or subsystem to wake up
135 * @ack Flag to specify whether acknowledge requested
136 * @set_address Resume address presence indicator
137 * 1 resume address specified, 0 otherwise
138 * @address Resume address
139 *
140 * This API function is either used to power up another APU core for SMP
141 * (by PSCI) or to power up an entirely different PU or subsystem, such
142 * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be
143 * automatically set by PMU.
144 *
145 * @return Returns status, either success or error+reason
146 */
147enum pm_ret_status pm_req_wakeup(enum pm_node_id target,
148 unsigned int set_address,
149 uintptr_t address,
150 enum pm_request_ack ack)
151{
152 uint32_t payload[PAYLOAD_ARG_CNT];
153 uint64_t encoded_address;
154 const struct pm_proc *proc = pm_get_proc_by_node(target);
155
156 /* invoke APU-specific code for waking up another APU core */
157 pm_client_wakeup(proc);
158
159 /* encode set Address into 1st bit of address */
160 encoded_address = address;
161 encoded_address |= !!set_address;
162
163 /* Send request to the PMU to perform the wake of the PU */
164 PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address,
165 encoded_address >> 32, ack);
166
167 if (ack == REQ_ACK_BLOCKING)
168 return pm_ipi_send_sync(primary_proc, payload, NULL);
169 else
170 return pm_ipi_send(primary_proc, payload);
171}
172
173/**
174 * pm_force_powerdown() - PM call to request for another PU or subsystem to
175 * be powered down forcefully
176 * @target Node id of the targeted PU or subsystem
177 * @ack Flag to specify whether acknowledge is requested
178 *
179 * @return Returns status, either success or error+reason
180 */
181enum pm_ret_status pm_force_powerdown(enum pm_node_id target,
182 enum pm_request_ack ack)
183{
184 uint32_t payload[PAYLOAD_ARG_CNT];
185
186 /* Send request to the PMU */
187 PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack);
188
189 if (ack == REQ_ACK_BLOCKING)
190 return pm_ipi_send_sync(primary_proc, payload, NULL);
191 else
192 return pm_ipi_send(primary_proc, payload);
193}
194
195/**
196 * pm_abort_suspend() - PM call to announce that a prior suspend request
197 * is to be aborted.
198 * @reason Reason for the abort
199 *
200 * Calling PU expects the PMU to abort the initiated suspend procedure.
201 * This is a non-blocking call without any acknowledge.
202 *
203 * @return Returns status, either success or error+reason
204 */
205enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
206{
207 uint32_t payload[PAYLOAD_ARG_CNT];
208
209 /*
210 * Do client specific abort suspend operations
211 * (e.g. enable interrupts and clear powerdown request bit)
212 */
213 pm_client_abort_suspend();
214 /* Send request to the PMU */
215 /* TODO: allow passing the node ID of the affected CPU */
216 PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason,
217 primary_proc->node_id);
218 return pm_ipi_send(primary_proc, payload);
219}
220
221/**
222 * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
223 * @target Node id of the targeted PU or subsystem
224 * @wkup_node Node id of the wakeup peripheral
225 * @enable Enable or disable the specified peripheral as wake source
226 *
227 * @return Returns status, either success or error+reason
228 */
229enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
230 enum pm_node_id wkup_node,
231 unsigned int enable)
232{
233 uint32_t payload[PAYLOAD_ARG_CNT];
234
235 PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node,
236 enable);
237 return pm_ipi_send(primary_proc, payload);
238}
239
240/**
241 * pm_system_shutdown() - PM call to request a system shutdown or restart
242 * @restart Shutdown or restart? 0 for shutdown, 1 for restart
243 *
244 * @return Returns status, either success or error+reason
245 */
246enum pm_ret_status pm_system_shutdown(unsigned int restart)
247{
248 uint32_t payload[PAYLOAD_ARG_CNT];
249
250 PM_PACK_PAYLOAD2(payload, PM_SYSTEM_SHUTDOWN, restart);
251 return pm_ipi_send(primary_proc, payload);
252}
253
254/* APIs for managing PM slaves: */
255
256/**
257 * pm_req_node() - PM call to request a node with specific capabilities
258 * @nid Node id of the slave
259 * @capabilities Requested capabilities of the slave
260 * @qos Quality of service (not supported)
261 * @ack Flag to specify whether acknowledge is requested
262 *
263 * @return Returns status, either success or error+reason
264 */
265enum pm_ret_status pm_req_node(enum pm_node_id nid,
266 unsigned int capabilities,
267 unsigned int qos,
268 enum pm_request_ack ack)
269{
270 uint32_t payload[PAYLOAD_ARG_CNT];
271
272 PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack);
273
274 if (ack == REQ_ACK_BLOCKING)
275 return pm_ipi_send_sync(primary_proc, payload, NULL);
276 else
277 return pm_ipi_send(primary_proc, payload);
278}
279
280/**
281 * pm_set_requirement() - PM call to set requirement for PM slaves
282 * @nid Node id of the slave
283 * @capabilities Requested capabilities of the slave
284 * @qos Quality of service (not supported)
285 * @ack Flag to specify whether acknowledge is requested
286 *
287 * This API function is to be used for slaves a PU already has requested
288 *
289 * @return Returns status, either success or error+reason
290 */
291enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
292 unsigned int capabilities,
293 unsigned int qos,
294 enum pm_request_ack ack)
295{
296 uint32_t payload[PAYLOAD_ARG_CNT];
297
298 PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos,
299 ack);
300
301 if (ack == REQ_ACK_BLOCKING)
302 return pm_ipi_send_sync(primary_proc, payload, NULL);
303 else
304 return pm_ipi_send(primary_proc, payload);
305}
306
307/**
308 * pm_release_node() - PM call to release a node
309 * @nid Node id of the slave
310 *
311 * @return Returns status, either success or error+reason
312 */
313enum pm_ret_status pm_release_node(enum pm_node_id nid)
314{
315 uint32_t payload[PAYLOAD_ARG_CNT];
316
317 PM_PACK_PAYLOAD2(payload, PM_RELEASE_NODE, nid);
318 return pm_ipi_send(primary_proc, payload);
319}
320
321/**
322 * pm_set_max_latency() - PM call to set wakeup latency requirements
323 * @nid Node id of the slave
324 * @latency Requested maximum wakeup latency
325 *
326 * @return Returns status, either success or error+reason
327 */
328enum pm_ret_status pm_set_max_latency(enum pm_node_id nid,
329 unsigned int latency)
330{
331 uint32_t payload[PAYLOAD_ARG_CNT];
332
333 PM_PACK_PAYLOAD3(payload, PM_SET_MAX_LATENCY, nid, latency);
334 return pm_ipi_send(primary_proc, payload);
335}
336
337/* Miscellaneous API functions */
338
339/**
340 * pm_get_api_version() - Get version number of PMU PM firmware
341 * @version Returns 32-bit version number of PMU Power Management Firmware
342 *
343 * @return Returns status, either success or error+reason
344 */
345enum pm_ret_status pm_get_api_version(unsigned int *version)
346{
347 uint32_t payload[PAYLOAD_ARG_CNT];
348
349 /* Send request to the PMU */
350 PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION);
351 return pm_ipi_send_sync(primary_proc, payload, version);
352}
353
354/**
355 * pm_set_configuration() - PM call to set system configuration
356 * @phys_addr Physical 32-bit address of data structure in memory
357 *
358 * @return Returns status, either success or error+reason
359 */
360enum pm_ret_status pm_set_configuration(unsigned int phys_addr)
361{
362 return PM_RET_ERROR_NOTSUPPORTED;
363}
364
365/**
366 * pm_get_node_status() - PM call to request a node's current power state
367 * @nid Node id of the slave
368 *
369 * @return Returns status, either success or error+reason
370 */
371enum pm_ret_status pm_get_node_status(enum pm_node_id nid)
372{
373 /* TODO: Add power state argument!! */
374 uint32_t payload[PAYLOAD_ARG_CNT];
375
376 PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid);
377 return pm_ipi_send(primary_proc, payload);
378}
379
380/**
381 * pm_register_notifier() - Register the PU to be notified of PM events
382 * @nid Node id of the slave
383 * @event The event to be notified about
384 * @wake Wake up on event
385 * @enable Enable or disable the notifier
386 *
387 * @return Returns status, either success or error+reason
388 */
389enum pm_ret_status pm_register_notifier(enum pm_node_id nid,
390 unsigned int event,
391 unsigned int wake,
392 unsigned int enable)
393{
Anes Hadziahmetagicc95ae092016-05-12 16:17:34 +0200394 uint32_t payload[PAYLOAD_ARG_CNT];
395
396 PM_PACK_PAYLOAD5(payload, PM_REGISTER_NOTIFIER,
397 nid, event, wake, enable);
398
399 return pm_ipi_send(primary_proc, payload);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800400}
401
402/**
Anes Hadziahmetagic92aee012016-05-12 16:17:30 +0200403 * pm_get_op_characteristic() - PM call to request operating characteristics
404 * of a node
405 * @nid Node id of the slave
406 * @type Type of the operating characteristic
407 * (power, temperature and latency)
408 * @result Returns the operating characteristic for the requested node,
409 * specified by the type
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800410 *
411 * @return Returns status, either success or error+reason
412 */
413enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
Anes Hadziahmetagic92aee012016-05-12 16:17:30 +0200414 enum pm_opchar_type type,
415 uint32_t *result)
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800416{
Anes Hadziahmetagic92aee012016-05-12 16:17:30 +0200417 uint32_t payload[PAYLOAD_ARG_CNT];
418
419 /* Send request to the PMU */
420 PM_PACK_PAYLOAD3(payload, PM_GET_OP_CHARACTERISTIC, nid, type);
421 return pm_ipi_send_sync(primary_proc, payload, result);
Soren Brinkmann76fcae32016-03-06 20:16:27 -0800422}
423
424/* Direct-Control API functions */
425
426/**
427 * pm_reset_assert() - Assert reset
428 * @reset Reset ID
429 * @assert Assert (1) or de-assert (0)
430 *
431 * @return Returns status, either success or error+reason
432 */
433enum pm_ret_status pm_reset_assert(unsigned int reset,
434 unsigned int assert)
435{
436 uint32_t payload[PAYLOAD_ARG_CNT];
437
438 /* Send request to the PMU */
439 PM_PACK_PAYLOAD3(payload, PM_RESET_ASSERT, reset, assert);
440 return pm_ipi_send(primary_proc, payload);
441}
442
443/**
444 * pm_reset_get_status() - Get current status of a reset line
445 * @reset Reset ID
446 * @reset_status Returns current status of selected reset line
447 *
448 * @return Returns status, either success or error+reason
449 */
450enum pm_ret_status pm_reset_get_status(unsigned int reset,
451 unsigned int *reset_status)
452{
453 uint32_t payload[PAYLOAD_ARG_CNT];
454
455 /* Send request to the PMU */
456 PM_PACK_PAYLOAD2(payload, PM_RESET_GET_STATUS, reset);
457 return pm_ipi_send_sync(primary_proc, payload, reset_status);
458}
459
460/**
461 * pm_mmio_write() - Perform write to protected mmio
462 * @address Address to write to
463 * @mask Mask to apply
464 * @value Value to write
465 *
466 * This function provides access to PM-related control registers
467 * that may not be directly accessible by a particular PU.
468 *
469 * @return Returns status, either success or error+reason
470 */
471enum pm_ret_status pm_mmio_write(uintptr_t address,
472 unsigned int mask,
473 unsigned int value)
474{
475 uint32_t payload[PAYLOAD_ARG_CNT];
476
477 /* Send request to the PMU */
478 PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value);
479 return pm_ipi_send(primary_proc, payload);
480}
481
482/**
483 * pm_mmio_read() - Read value from protected mmio
484 * @address Address to write to
485 * @value Value to write
486 *
487 * This function provides access to PM-related control registers
488 * that may not be directly accessible by a particular PU.
489 *
490 * @return Returns status, either success or error+reason
491 */
492enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value)
493{
494 uint32_t payload[PAYLOAD_ARG_CNT];
495
496 /* Send request to the PMU */
497 PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address);
498 return pm_ipi_send_sync(primary_proc, payload, value);
499}