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