1 /*
2  * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * ZynqMP system level PM-API functions and communication with PMU via
9  * IPI interrupts
10  */
11 
12 #include <arch_helpers.h>
13 #include <platform.h>
14 #include "pm_api_sys.h"
15 #include "pm_client.h"
16 #include "pm_common.h"
17 #include "pm_ipi.h"
18 
19 /**
20  * Assigning of argument values into array elements.
21  */
22 #define PM_PACK_PAYLOAD1(pl, arg0) {	\
23 	pl[0] = (uint32_t)(arg0);	\
24 }
25 
26 #define PM_PACK_PAYLOAD2(pl, arg0, arg1) {	\
27 	pl[1] = (uint32_t)(arg1);		\
28 	PM_PACK_PAYLOAD1(pl, arg0);		\
29 }
30 
31 #define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) {	\
32 	pl[2] = (uint32_t)(arg2);			\
33 	PM_PACK_PAYLOAD2(pl, arg0, arg1);		\
34 }
35 
36 #define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) {	\
37 	pl[3] = (uint32_t)(arg3);			\
38 	PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2);		\
39 }
40 
41 #define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) {	\
42 	pl[4] = (uint32_t)(arg4);				\
43 	PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3);		\
44 }
45 
46 #define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) {	\
47 	pl[5] = (uint32_t)(arg5);					\
48 	PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4);		\
49 }
50 
51 /**
52  * pm_self_suspend() - PM call for processor to suspend itself
53  * @nid		Node id of the processor or subsystem
54  * @latency	Requested maximum wakeup latency (not supported)
55  * @state	Requested state
56  * @address	Resume address
57  *
58  * This is a blocking call, it will return only once PMU has responded.
59  * On a wakeup, resume address will be automatically set by PMU.
60  *
61  * @return	Returns status, either success or error+reason
62  */
pm_self_suspend(enum pm_node_id nid,unsigned int latency,unsigned int state,uintptr_t address)63 enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
64 				   unsigned int latency,
65 				   unsigned int state,
66 				   uintptr_t address)
67 {
68 	uint32_t payload[PAYLOAD_ARG_CNT];
69 	unsigned int cpuid = plat_my_core_pos();
70 	const struct pm_proc *proc = pm_get_proc(cpuid);
71 
72 	/*
73 	 * Do client specific suspend operations
74 	 * (e.g. set powerdown request bit)
75 	 */
76 	pm_client_suspend(proc, state);
77 	/* Send request to the PMU */
78 	PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency,
79 			 state, address, (address >> 32));
80 	return pm_ipi_send_sync(proc, payload, NULL, 0);
81 }
82 
83 /**
84  * pm_req_suspend() - PM call to request for another PU or subsystem to
85  *		      be suspended gracefully.
86  * @target	Node id of the targeted PU or subsystem
87  * @ack		Flag to specify whether acknowledge is requested
88  * @latency	Requested wakeup latency (not supported)
89  * @state	Requested state (not supported)
90  *
91  * @return	Returns status, either success or error+reason
92  */
pm_req_suspend(enum pm_node_id target,enum pm_request_ack ack,unsigned int latency,unsigned int state)93 enum pm_ret_status pm_req_suspend(enum pm_node_id target,
94 				  enum pm_request_ack ack,
95 				  unsigned int latency, unsigned int state)
96 {
97 	uint32_t payload[PAYLOAD_ARG_CNT];
98 
99 	/* Send request to the PMU */
100 	PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state);
101 	if (ack == REQ_ACK_BLOCKING)
102 		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
103 	else
104 		return pm_ipi_send(primary_proc, payload);
105 }
106 
107 /**
108  * pm_req_wakeup() - PM call for processor to wake up selected processor
109  *		     or subsystem
110  * @target	Node id of the processor or subsystem to wake up
111  * @ack		Flag to specify whether acknowledge requested
112  * @set_address	Resume address presence indicator
113  *				1 resume address specified, 0 otherwise
114  * @address	Resume address
115  *
116  * This API function is either used to power up another APU core for SMP
117  * (by PSCI) or to power up an entirely different PU or subsystem, such
118  * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be
119  * automatically set by PMU.
120  *
121  * @return	Returns status, either success or error+reason
122  */
pm_req_wakeup(enum pm_node_id target,unsigned int set_address,uintptr_t address,enum pm_request_ack ack)123 enum pm_ret_status pm_req_wakeup(enum pm_node_id target,
124 				 unsigned int set_address,
125 				 uintptr_t address,
126 				 enum pm_request_ack ack)
127 {
128 	uint32_t payload[PAYLOAD_ARG_CNT];
129 	uint64_t encoded_address;
130 	const struct pm_proc *proc = pm_get_proc_by_node(target);
131 
132 	/* invoke APU-specific code for waking up another APU core */
133 	pm_client_wakeup(proc);
134 
135 	/* encode set Address into 1st bit of address */
136 	encoded_address = address;
137 	encoded_address |= !!set_address;
138 
139 	/* Send request to the PMU to perform the wake of the PU */
140 	PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address,
141 			 encoded_address >> 32, ack);
142 
143 	if (ack == REQ_ACK_BLOCKING)
144 		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
145 	else
146 		return pm_ipi_send(primary_proc, payload);
147 }
148 
149 /**
150  * pm_force_powerdown() - PM call to request for another PU or subsystem to
151  *			  be powered down forcefully
152  * @target	Node id of the targeted PU or subsystem
153  * @ack		Flag to specify whether acknowledge is requested
154  *
155  * @return	Returns status, either success or error+reason
156  */
pm_force_powerdown(enum pm_node_id target,enum pm_request_ack ack)157 enum pm_ret_status pm_force_powerdown(enum pm_node_id target,
158 				      enum pm_request_ack ack)
159 {
160 	uint32_t payload[PAYLOAD_ARG_CNT];
161 
162 	/* Send request to the PMU */
163 	PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack);
164 
165 	if (ack == REQ_ACK_BLOCKING)
166 		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
167 	else
168 		return pm_ipi_send(primary_proc, payload);
169 }
170 
171 /**
172  * pm_abort_suspend() - PM call to announce that a prior suspend request
173  *			is to be aborted.
174  * @reason	Reason for the abort
175  *
176  * Calling PU expects the PMU to abort the initiated suspend procedure.
177  * This is a non-blocking call without any acknowledge.
178  *
179  * @return	Returns status, either success or error+reason
180  */
pm_abort_suspend(enum pm_abort_reason reason)181 enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
182 {
183 	uint32_t payload[PAYLOAD_ARG_CNT];
184 
185 	/*
186 	 * Do client specific abort suspend operations
187 	 * (e.g. enable interrupts and clear powerdown request bit)
188 	 */
189 	pm_client_abort_suspend();
190 	/* Send request to the PMU */
191 	/* TODO: allow passing the node ID of the affected CPU */
192 	PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason,
193 			 primary_proc->node_id);
194 	return pm_ipi_send(primary_proc, payload);
195 }
196 
197 /**
198  * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
199  * @target	Node id of the targeted PU or subsystem
200  * @wkup_node	Node id of the wakeup peripheral
201  * @enable	Enable or disable the specified peripheral as wake source
202  *
203  * @return	Returns status, either success or error+reason
204  */
pm_set_wakeup_source(enum pm_node_id target,enum pm_node_id wkup_node,unsigned int enable)205 enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
206 					enum pm_node_id wkup_node,
207 					unsigned int enable)
208 {
209 	uint32_t payload[PAYLOAD_ARG_CNT];
210 
211 	PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node,
212 			 enable);
213 	return pm_ipi_send(primary_proc, payload);
214 }
215 
216 /**
217  * pm_system_shutdown() - PM call to request a system shutdown or restart
218  * @restart	Shutdown or restart? 0 for shutdown, 1 for restart
219  *
220  * @return	Returns status, either success or error+reason
221  */
pm_system_shutdown(unsigned int type,unsigned int subtype)222 enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype)
223 {
224 	uint32_t payload[PAYLOAD_ARG_CNT];
225 
226 	PM_PACK_PAYLOAD3(payload, PM_SYSTEM_SHUTDOWN, type, subtype);
227 	return pm_ipi_send(primary_proc, payload);
228 }
229 
230 /* APIs for managing PM slaves: */
231 
232 /**
233  * pm_req_node() - PM call to request a node with specific capabilities
234  * @nid		Node id of the slave
235  * @capabilities Requested capabilities of the slave
236  * @qos		Quality of service (not supported)
237  * @ack		Flag to specify whether acknowledge is requested
238  *
239  * @return	Returns status, either success or error+reason
240  */
pm_req_node(enum pm_node_id nid,unsigned int capabilities,unsigned int qos,enum pm_request_ack ack)241 enum pm_ret_status pm_req_node(enum pm_node_id nid,
242 			       unsigned int capabilities,
243 			       unsigned int qos,
244 			       enum pm_request_ack ack)
245 {
246 	uint32_t payload[PAYLOAD_ARG_CNT];
247 
248 	PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack);
249 
250 	if (ack == REQ_ACK_BLOCKING)
251 		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
252 	else
253 		return pm_ipi_send(primary_proc, payload);
254 }
255 
256 /**
257  * pm_set_requirement() - PM call to set requirement for PM slaves
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  * This API function is to be used for slaves a PU already has requested
264  *
265  * @return	Returns status, either success or error+reason
266  */
pm_set_requirement(enum pm_node_id nid,unsigned int capabilities,unsigned int qos,enum pm_request_ack ack)267 enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
268 				      unsigned int capabilities,
269 				      unsigned int qos,
270 				      enum pm_request_ack ack)
271 {
272 	uint32_t payload[PAYLOAD_ARG_CNT];
273 
274 	PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos,
275 			 ack);
276 
277 	if (ack == REQ_ACK_BLOCKING)
278 		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
279 	else
280 		return pm_ipi_send(primary_proc, payload);
281 }
282 
283 /**
284  * pm_release_node() - PM call to release a node
285  * @nid		Node id of the slave
286  *
287  * @return	Returns status, either success or error+reason
288  */
pm_release_node(enum pm_node_id nid)289 enum pm_ret_status pm_release_node(enum pm_node_id nid)
290 {
291 	uint32_t payload[PAYLOAD_ARG_CNT];
292 
293 	PM_PACK_PAYLOAD2(payload, PM_RELEASE_NODE, nid);
294 	return pm_ipi_send(primary_proc, payload);
295 }
296 
297 /**
298  * pm_set_max_latency() - PM call to set wakeup latency requirements
299  * @nid		Node id of the slave
300  * @latency	Requested maximum wakeup latency
301  *
302  * @return	Returns status, either success or error+reason
303  */
pm_set_max_latency(enum pm_node_id nid,unsigned int latency)304 enum pm_ret_status pm_set_max_latency(enum pm_node_id nid,
305 				      unsigned int latency)
306 {
307 	uint32_t payload[PAYLOAD_ARG_CNT];
308 
309 	PM_PACK_PAYLOAD3(payload, PM_SET_MAX_LATENCY, nid, latency);
310 	return pm_ipi_send(primary_proc, payload);
311 }
312 
313 /* Miscellaneous API functions */
314 
315 /**
316  * pm_get_api_version() - Get version number of PMU PM firmware
317  * @version	Returns 32-bit version number of PMU Power Management Firmware
318  *
319  * @return	Returns status, either success or error+reason
320  */
pm_get_api_version(unsigned int * version)321 enum pm_ret_status pm_get_api_version(unsigned int *version)
322 {
323 	uint32_t payload[PAYLOAD_ARG_CNT];
324 
325 	/* Send request to the PMU */
326 	PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION);
327 	return pm_ipi_send_sync(primary_proc, payload, version, 1);
328 }
329 
330 /**
331  * pm_set_configuration() - PM call to set system configuration
332  * @phys_addr	Physical 32-bit address of data structure in memory
333  *
334  * @return	Returns status, either success or error+reason
335  */
pm_set_configuration(unsigned int phys_addr)336 enum pm_ret_status pm_set_configuration(unsigned int phys_addr)
337 {
338 	return PM_RET_ERROR_NOTSUPPORTED;
339 }
340 
341 /**
342  * pm_get_node_status() - PM call to request a node's current power state
343  * @nid		Node id of the slave
344  *
345  * @return	Returns status, either success or error+reason
346  */
pm_get_node_status(enum pm_node_id nid)347 enum pm_ret_status pm_get_node_status(enum pm_node_id nid)
348 {
349 	/* TODO: Add power state argument!! */
350 	uint32_t payload[PAYLOAD_ARG_CNT];
351 
352 	PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid);
353 	return pm_ipi_send(primary_proc, payload);
354 }
355 
356 /**
357  * pm_register_notifier() - Register the PU to be notified of PM events
358  * @nid		Node id of the slave
359  * @event	The event to be notified about
360  * @wake	Wake up on event
361  * @enable	Enable or disable the notifier
362  *
363  * @return	Returns status, either success or error+reason
364  */
pm_register_notifier(enum pm_node_id nid,unsigned int event,unsigned int wake,unsigned int enable)365 enum pm_ret_status pm_register_notifier(enum pm_node_id nid,
366 					unsigned int event,
367 					unsigned int wake,
368 					unsigned int enable)
369 {
370 	uint32_t payload[PAYLOAD_ARG_CNT];
371 
372 	PM_PACK_PAYLOAD5(payload, PM_REGISTER_NOTIFIER,
373 			 nid, event, wake, enable);
374 
375 	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
376 }
377 
378 /**
379  * pm_get_op_characteristic() - PM call to request operating characteristics
380  *				of a node
381  * @nid		Node id of the slave
382  * @type	Type of the operating characteristic
383  *		(power, temperature and latency)
384  * @result	Returns the operating characteristic for the requested node,
385  *		specified by the type
386  *
387  * @return	Returns status, either success or error+reason
388  */
pm_get_op_characteristic(enum pm_node_id nid,enum pm_opchar_type type,uint32_t * result)389 enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
390 					    enum pm_opchar_type type,
391 					    uint32_t *result)
392 {
393 	uint32_t payload[PAYLOAD_ARG_CNT];
394 
395 	/* Send request to the PMU */
396 	PM_PACK_PAYLOAD3(payload, PM_GET_OP_CHARACTERISTIC, nid, type);
397 	return pm_ipi_send_sync(primary_proc, payload, result, 1);
398 }
399 
400 /* Direct-Control API functions */
401 
402 /**
403  * pm_reset_assert() - Assert reset
404  * @reset	Reset ID
405  * @assert	Assert (1) or de-assert (0)
406  *
407  * @return	Returns status, either success or error+reason
408  */
pm_reset_assert(unsigned int reset,unsigned int assert)409 enum pm_ret_status pm_reset_assert(unsigned int reset,
410 				   unsigned int assert)
411 {
412 	uint32_t payload[PAYLOAD_ARG_CNT];
413 
414 	/* Send request to the PMU */
415 	PM_PACK_PAYLOAD3(payload, PM_RESET_ASSERT, reset, assert);
416 	return pm_ipi_send(primary_proc, payload);
417 }
418 
419 /**
420  * pm_reset_get_status() - Get current status of a reset line
421  * @reset	Reset ID
422  * @reset_status Returns current status of selected reset line
423  *
424  * @return	Returns status, either success or error+reason
425  */
pm_reset_get_status(unsigned int reset,unsigned int * reset_status)426 enum pm_ret_status pm_reset_get_status(unsigned int reset,
427 				       unsigned int *reset_status)
428 {
429 	uint32_t payload[PAYLOAD_ARG_CNT];
430 
431 	/* Send request to the PMU */
432 	PM_PACK_PAYLOAD2(payload, PM_RESET_GET_STATUS, reset);
433 	return pm_ipi_send_sync(primary_proc, payload, reset_status, 1);
434 }
435 
436 /**
437  * pm_mmio_write() - Perform write to protected mmio
438  * @address	Address to write to
439  * @mask	Mask to apply
440  * @value	Value to write
441  *
442  * This function provides access to PM-related control registers
443  * that may not be directly accessible by a particular PU.
444  *
445  * @return	Returns status, either success or error+reason
446  */
pm_mmio_write(uintptr_t address,unsigned int mask,unsigned int value)447 enum pm_ret_status pm_mmio_write(uintptr_t address,
448 				 unsigned int mask,
449 				 unsigned int value)
450 {
451 	uint32_t payload[PAYLOAD_ARG_CNT];
452 
453 	/* Send request to the PMU */
454 	PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value);
455 	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
456 }
457 
458 /**
459  * pm_mmio_read() - Read value from protected mmio
460  * @address	Address to write to
461  * @value	Value to write
462  *
463  * This function provides access to PM-related control registers
464  * that may not be directly accessible by a particular PU.
465  *
466  * @return	Returns status, either success or error+reason
467  */
pm_mmio_read(uintptr_t address,unsigned int * value)468 enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value)
469 {
470 	uint32_t payload[PAYLOAD_ARG_CNT];
471 
472 	/* Send request to the PMU */
473 	PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address);
474 	return pm_ipi_send_sync(primary_proc, payload, value, 1);
475 }
476 
477 /**
478  * pm_fpga_load() - Load the bitstream into the PL.
479  *
480  * This function provides access to the xilfpga library to load
481  * the Bit-stream into PL.
482  *
483  * address_low: lower 32-bit Linear memory space address
484  *
485  * address_high: higher 32-bit Linear memory space address
486  *
487  * size:	Number of 32bit words
488  *
489  * @return      Returns status, either success or error+reason
490  */
pm_fpga_load(uint32_t address_low,uint32_t address_high,uint32_t size,uint32_t flags)491 enum pm_ret_status pm_fpga_load(uint32_t address_low,
492 				uint32_t address_high,
493 				uint32_t size,
494 				uint32_t flags)
495 {
496 	uint32_t payload[PAYLOAD_ARG_CNT];
497 
498 	/* Send request to the PMU */
499 	PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low,
500 						size, flags);
501 	return pm_ipi_send(primary_proc, payload);
502 }
503 
504 /**
505  * pm_fpga_get_status() - Read value from fpga status register
506  * @value       Value to read
507  *
508  * This function provides access to the xilfpga library to get
509  * the fpga status
510  * @return      Returns status, either success or error+reason
511  */
pm_fpga_get_status(unsigned int * value)512 enum pm_ret_status pm_fpga_get_status(unsigned int *value)
513 {
514 	uint32_t payload[PAYLOAD_ARG_CNT];
515 
516 	/* Send request to the PMU */
517 	PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS);
518 	return pm_ipi_send_sync(primary_proc, payload, value, 1);
519 }
520 
521 /**
522  * pm_get_chipid() - Read silicon ID registers
523  * @value       Buffer for return values. Must be large enough
524  *		to hold 8 bytes.
525  *
526  * @return      Returns silicon ID registers
527  */
pm_get_chipid(uint32_t * value)528 enum pm_ret_status pm_get_chipid(uint32_t *value)
529 {
530 	uint32_t payload[PAYLOAD_ARG_CNT];
531 
532 	/* Send request to the PMU */
533 	PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID);
534 	return pm_ipi_send_sync(primary_proc, payload, value, 2);
535 }
536 
537 /**
538  * pm_get_callbackdata() - Read from IPI response buffer
539  * @data - array of PAYLOAD_ARG_CNT elements
540  *
541  * Read value from ipi buffer response buffer.
542  */
pm_get_callbackdata(uint32_t * data,size_t count)543 void pm_get_callbackdata(uint32_t *data, size_t count)
544 {
545 
546 	pm_ipi_buff_read_callb(data, count);
547 	pm_ipi_irq_clear();
548 }
549