Home | History | Annotate | Download | only in pm_service
      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  */
     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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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