1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /** 3 * Copyright 2019-2024 NXP 4 * 5 * KEYWORDS: micro-power uPower driver API 6 */ 7 8 #include <string.h> 9 10 #include "upower_api.h" 11 #include "upower_soc_defs.h" 12 13 /* --------------------------------------------------------------- 14 * Common Macros 15 * --------------------------------------------------------------- 16 */ 17 18 /* tests Service Group busy */ 19 #define UPWR_SG_BUSY(sg) ((sg_busy & (1U << (sg))) == 1U) 20 21 /* install user callback for the Service Group */ 22 #define UPWR_USR_CALLB(sg, cb) { user_callback[(sg)] = (cb); } 23 24 /* fills up common message header info */ 25 #define UPWR_MSG_HDR(hdr, sg, fn) { \ 26 (hdr).domain = (uint32_t)pwr_domain; \ 27 (hdr).srvgrp = (sg); \ 28 (hdr).function = (fn); } 29 30 /* --------------------------------------------------------------- 31 * Common Data Structures 32 * --------------------------------------------------------------- 33 */ 34 static soc_domain_t pwr_domain; 35 36 static upwr_code_vers_t fw_rom_version; 37 static upwr_code_vers_t fw_ram_version; 38 static uint32_t fw_launch_option; 39 40 /* shared memory buffers */ 41 #define UPWR_API_BUFFER_SIZE (MAX_SG_EXCEPT_MEM_SIZE + \ 42 MAX_SG_PWRMGMT_MEM_SIZE + MAX_SG_VOLTM_MEM_SIZE) 43 44 /* service group shared mem buffer pointers */ 45 static void *sh_buffer[UPWR_SG_COUNT]; 46 47 /* Callbacks registered for each service group : 48 * 49 * NULL means no callback is registered; 50 * for sgrp_callback, it also means the service group is 51 * free to receive a new request. 52 */ 53 static upwr_callb user_callback[UPWR_SG_COUNT]; 54 static UPWR_RX_CALLB_FUNC_T sgrp_callback[UPWR_SG_COUNT]; 55 56 /* request data structures for each service group */ 57 /* message waiting for TX */ 58 static upwr_down_max_msg sg_req_msg[UPWR_SG_COUNT]; 59 /* waiting message size */ 60 static unsigned int sg_req_siz[UPWR_SG_COUNT]; 61 /* response msg */ 62 static upwr_up_max_msg sg_rsp_msg[UPWR_SG_COUNT]; 63 /* response msg size */ 64 static unsigned int sg_rsp_siz[UPWR_SG_COUNT]; 65 66 /* tx pending status for each (1 bit per service group) */ 67 static volatile uint32_t sg_tx_pend; 68 /* serv.group of current ongoing Tx, if any */ 69 static volatile upwr_sg_t sg_tx_curr; 70 71 /* service group busy status, only for this domain (MU index 0) */ 72 /* SG bit = 1 if group is busy with a request */ 73 static volatile uint32_t sg_busy; 74 75 /* OS-dependent memory allocation function */ 76 static upwr_malloc_ptr_t os_malloc; 77 /* OS-dependent pointer->physical address conversion function */ 78 static upwr_phyadr_ptr_t os_ptr2phy; 79 /* OS-dependent function to lock critical code */ 80 static upwr_lock_ptr_t os_lock; 81 82 /* pointer to MU structure */ 83 static struct MU_t *mu; 84 85 /* 86 * indicates that a transmission was done and is pending; this 87 * bit is necessary because the Tx and Rx interrupts are ORed 88 * together, and there is no way of telling if only Rx interrupt 89 * or both occurred just by looking at the MU status registers 90 */ 91 static uint32_t mu_tx_pend; 92 93 static UPWR_TX_CALLB_FUNC_T mu_tx_callb; 94 static UPWR_RX_CALLB_FUNC_T mu_rx_callb; 95 96 #define UPWR_API_INIT_WAIT (0U) /* waiting for ROM firmware initialization */ 97 #define UPWR_API_INITLZED (1U) /* ROM firmware initialized */ 98 #define UPWR_API_START_WAIT (2U) /* waiting for start services */ 99 #define UPWR_API_SHUTDOWN_WAIT (3U) /* waiting for shutdown */ 100 #define UPWR_API_READY (4U) /* ready to receive service requests */ 101 102 volatile upwr_api_state_t api_state; 103 104 /* default pointer->physical address conversion, returns the same address */ 105 static void *ptr2phys(const void *ptr) 106 { 107 return (void *)ptr; 108 } 109 110 /* --------------------------------------------------------------- 111 * SHARED MEMORY MANAGEMENT 112 * -------------------------------------------------------------- 113 */ 114 115 /* 116 * upwr_ptr2offset() - converts a pointer (casted to uint64_t) to an 117 * address offset from the shared memory start. If it does not point 118 * to a shared memory location, the structure pointed is copied to a 119 * buffer in the shared memory, and the buffer offset is returned. 120 * The 2nd argument is the service group to which the buffer belongs; 121 * The 3rd argument is the size of structure to be copied. The 4th argument 122 * is an offset to apply to the copy destination address. The 5th argument 123 * is ptr before the conversion to physical address. 2nd, 3rd. 4th and 5th 124 * arguments are not used if the 1st one points to a location inside the 125 * shared memory. 126 */ 127 128 static uint32_t upwr_ptr2offset(unsigned long ptr, 129 upwr_sg_t sg, 130 size_t siz, 131 size_t offset, 132 const void *vptr) 133 { 134 if ((ptr >= UPWR_DRAM_SHARED_BASE_ADDR) && 135 ((ptr - UPWR_DRAM_SHARED_BASE_ADDR) < UPWR_DRAM_SHARED_SIZE)) { 136 return (uint32_t)(ptr - UPWR_DRAM_SHARED_BASE_ADDR); 137 } 138 139 /* pointer is outside the shared memory, copy the struct to buffer */ 140 (void)memcpy((void *)(offset + (char *)sh_buffer[sg]), (void *)vptr, siz); 141 return (uint32_t)((unsigned long)sh_buffer[sg] + offset - UPWR_DRAM_SHARED_BASE_ADDR); 142 } 143 144 /* 145 * --------------------------------------------------------------- 146 * INTERRUPTS AND CALLBACKS 147 * Service-group specific callbacks are in their own sections 148 * -------------------------------------------------------------- 149 */ 150 151 /* 152 * upwr_lock()- locks (lock=1) or unlocks (lock=0) a critical code section; 153 * for now it only needs to protect a portion of the code from being 154 * interrupted by the MU. 155 */ 156 static void upwr_lock(int lock) 157 { 158 if (os_lock != NULL) { 159 os_lock(lock); 160 } 161 } 162 163 /* upwr_exp_isr()- handles the exception interrupt from uPower */ 164 static void upwr_exp_isr(void) 165 { 166 } 167 168 /* upwr_copy2tr prototype; function definition in auxiliary function section */ 169 void upwr_copy2tr(struct MU_t *local_mu, const uint32_t *msg, unsigned int size); 170 171 #define UPWR_MU_TSR_EMPTY ((uint32_t)((1UL << UPWR_MU_MSG_SIZE) - 1UL)) 172 173 /* upwr_txrx_isr()- handles both the Tx and Rx MU interrupts */ 174 void upwr_txrx_isr(void) 175 { 176 /* Tx pending and TX register empty */ 177 if ((mu_tx_pend != 0UL) && (mu->TSR.R == UPWR_MU_TSR_EMPTY)) { 178 mu_tx_pend = 0UL; 179 /* disable the tx interrupts */ 180 mu->TCR.R = 0U; 181 /* urgency flag off, in case it was set */ 182 mu->FCR.B.F0 = 0U; 183 184 if (mu_tx_callb != NULL) { 185 mu_tx_callb(); 186 } 187 } 188 189 /* RX ISR occurred */ 190 if (mu->RSR.R != 0UL) { 191 /* disable the interrupt until data is read */ 192 mu->RCR.R = 0U; 193 194 if (mu_rx_callb != NULL) { 195 mu_rx_callb(); 196 } 197 } 198 } 199 200 /** 201 * upwr_next_req() - sends the next pending service request message, if any. 202 * 203 * Called upon MU Tx interrupts, it checks if there is any service request 204 * pending amongst the service groups, and sends the request if needed. 205 * 206 * Context: no sleep, no locks taken/released. 207 * Return: none (void). 208 */ 209 static void upwr_next_req(void) 210 { 211 upwr_sg_t sg = (upwr_sg_t)0U; 212 213 /* no lock needed here, this is called from an MU ISR */ 214 sg_tx_pend &= ~((uint32_t)1UL << sg_tx_curr); /* no longer pending */ 215 216 if (sg_tx_pend == 0U) { 217 return; /* no other pending */ 218 } 219 220 /* find the next one pending */ 221 for (uint32_t mask = 1UL; mask < (1UL << UPWR_SG_COUNT); mask = mask << 1UL) { 222 if ((sg_tx_pend & mask) != 0U) { 223 break; 224 } 225 226 sg = (upwr_sg_t)(sg + 1U); 227 } 228 229 sg_tx_curr = sg; 230 if (upwr_tx((uint32_t *)&sg_req_msg[sg], sg_req_siz[sg], upwr_next_req) < 0) { 231 return; /* leave the Tx pending */ 232 } 233 } 234 235 /** 236 * upwr_mu_int_callback() - general MU interrupt callback. 237 * 238 * Called upon MU Rx interrupts, it calls the Service Group-specific callback, 239 * if any registered, based on the service group field in the received message. 240 * Otherwise, calls the user callback, if any registered. 241 * 242 * Context: no sleep, no locks taken/released. 243 * Return: none (void). 244 */ 245 static void upwr_mu_int_callback(void) 246 { 247 upwr_sg_t sg; /* service group number */ 248 UPWR_RX_CALLB_FUNC_T sg_callb; /* service group callback */ 249 upwr_up_max_msg rxmsg = {0}; 250 unsigned int size; /* in words */ 251 252 if (upwr_rx((char *)&rxmsg, &size) < 0) { 253 return; 254 } 255 256 sg = (upwr_sg_t)rxmsg.hdr.srvgrp; 257 258 /* copy msg to the service group buffer */ 259 msg_copy((char *)&sg_rsp_msg[sg], (char *)&rxmsg, size); 260 sg_rsp_siz[sg] = size; 261 262 /* clear the service group busy status */ 263 sg_busy &= ~(1UL << sg); /* no lock needed here, we're in the MU ISR */ 264 265 sg_callb = sgrp_callback[sg]; 266 if (sg_callb == NULL) { 267 upwr_callb user_callb = user_callback[sg]; 268 /* no service group callback; call the user callback if any */ 269 if (user_callb == NULL) { 270 goto done; /* no user callback */ 271 } 272 273 /* make the user callback */ 274 user_callb(sg, rxmsg.hdr.function, 275 (upwr_resp_t)rxmsg.hdr.errcode, 276 (size == 2U) ? rxmsg.word2 : rxmsg.hdr.ret); 277 goto done; 278 } 279 280 /* 281 * finally make the group callback. don't uninstall the group 282 * callback, it is permanent. 283 */ 284 sg_callb(); 285 done: 286 if (rxmsg.hdr.errcode == UPWR_RESP_SHUTDOWN) { /* shutdown error: */ 287 /* 288 * change the API state automatically. so new requests 289 * are rejected by the API immediately 290 */ 291 api_state = UPWR_API_INITLZED; 292 } 293 } 294 295 /** 296 * upwr_srv_req() - sends a service request message. 297 * @sg: message service group. 298 * @msg: pointer to the message 299 * @size: message size in 32-bit words. 300 * 301 * The message is sent right away if possible, or gets pending to be sent later. 302 * If pending, the message is stored in sg_req_msg and will be sent when the 303 * MU transmission buffer is clear and there are no other pending messages 304 * from higher priority service groups. 305 * 306 * This is an auxiliary function used by the rest of the API calls. 307 * It is normally not called by the driver code, unless maybe for test purposes. 308 * 309 * Context: no sleep, no locks taken/released. 310 * Return: none (void) 311 */ 312 static void upwr_srv_req(upwr_sg_t sg, 313 uint32_t *msg, 314 unsigned int size) 315 { 316 int rc; 317 318 upwr_lock(1); 319 sg_busy |= (uint32_t)1U << sg; 320 upwr_lock(0); 321 322 rc = upwr_tx(msg, size, upwr_next_req); 323 if (rc < 0) { 324 /* queue full, make the transmission pending */ 325 msg_copy((char *)&sg_req_msg[sg], (char *)msg, size); 326 sg_req_siz[sg] = size; 327 328 upwr_lock(1); 329 sg_tx_curr = sg; 330 sg_tx_pend |= (uint32_t)1U << sg; 331 upwr_lock(0); 332 333 return; 334 } 335 } 336 337 /**--------------------------------------------------------------- 338 * INITIALIZATION, CONFIGURATION 339 * 340 * A reference uPower initialization sequence goes as follows: 341 * 342 * 1. host CPU calls upwr_init. 343 * 2. (optional) host checks the ROM version and SoC code calling upwr_vers(...) 344 * and optionally performs any configuration or workaround accordingly. 345 * 3. host CPU calls upwr_start to start the uPower services, passing a 346 * service option number. 347 * If no RAM code is loaded or it has no service options, the launch option 348 * number passed must be 0, which will start the services available in ROM. 349 * upwr_start also receives a pointer to a callback called by the API 350 * when the firmware is ready to receive service requests. 351 * The callback may be replaced by polling, calling upwr_req_status in a loop 352 * or upwr_poll_req_status; in this case the callback pointer may be NULL. 353 * A host may call upwr_start even if the services were already started by 354 * any host: if the launch option is the same, the response will be ok, 355 * but will indicate error if the services were already started with a 356 * different launch option. 357 * 4. host waits for the callback calling, or polling finishing; 358 * if no error is returned, it can start making service calls using the API. 359 * 360 * Variations on that reference sequence are possible: 361 * - the uPower services can be started using the ROM code only, which includes 362 * the basic Power Management services, among others, with launch option 363 * number = 0. 364 * The code RAM can be loaded while these services are running and, 365 * when the loading is done, the services can be re-started with these 2 366 * requests executed in order: upwr_xcp_shutdown and upwr_start, 367 * using the newly loaded RAM code (launch option > 0). 368 * 369 * NOTE: the initialization call upwr_init is not effective and 370 * returns error when called after the uPower services are started. 371 */ 372 373 /** 374 * upwr_start_callb() - internal callback for the Rx message from uPower 375 * that indicates the firmware is ready to receive the start commands. 376 * It calls the user callbacks registered in the upwr_start_boot and upwr_start 377 * call. 378 */ 379 void upwr_start_callb(void) 380 { 381 switch (api_state) { 382 case UPWR_API_START_WAIT: { 383 upwr_rdy_callb start_callb = (upwr_rdy_callb)user_callback[UPWR_SG_EXCEPT]; 384 upwr_ready_msg *msg = (upwr_ready_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT]; 385 386 fw_ram_version.soc_id = fw_rom_version.soc_id; 387 fw_ram_version.vmajor = msg->args.vmajor; 388 fw_ram_version.vminor = msg->args.vminor; 389 fw_ram_version.vfixes = msg->args.vfixes; 390 391 /* 392 * vmajor == vminor == vfixes == 0 indicates start error 393 * in this case, go back to the INITLZED state 394 */ 395 if ((fw_ram_version.vmajor != 0U) || 396 (fw_ram_version.vminor != 0U) || 397 (fw_ram_version.vfixes != 0U)) { 398 api_state = UPWR_API_READY; 399 400 /* 401 * initialization is over: 402 * uninstall the user callback just in case 403 */ 404 UPWR_USR_CALLB(UPWR_SG_EXCEPT, NULL); 405 406 if (fw_launch_option == 0U) { 407 /* 408 * launched ROM firmware: 409 * RAM fw versions must be all 0s 410 */ 411 fw_ram_version.vmajor = 0U; 412 fw_ram_version.vminor = 0U; 413 fw_ram_version.vfixes = 0U; 414 } 415 } else { 416 api_state = UPWR_API_INITLZED; 417 } 418 419 start_callb(msg->args.vmajor, msg->args.vminor, msg->args.vfixes); 420 } 421 break; 422 423 case UPWR_API_SHUTDOWN_WAIT: { 424 upwr_callb user_callb = (upwr_callb)user_callback[UPWR_SG_EXCEPT]; 425 upwr_shutdown_msg *msg = (upwr_shutdown_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT]; 426 427 if ((upwr_resp_t)msg->hdr.errcode == UPWR_RESP_OK) { 428 api_state = UPWR_API_INITLZED; 429 } 430 431 if (user_callb != NULL) { 432 user_callb(UPWR_SG_EXCEPT, UPWR_XCP_SHUTDOWN, 433 (upwr_resp_t)msg->hdr.errcode, 0U); 434 } 435 } 436 break; 437 438 case UPWR_API_READY: 439 { 440 upwr_callb user_callb = (upwr_callb)user_callback[UPWR_SG_EXCEPT]; 441 upwr_up_max_msg *msg = (upwr_up_max_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT]; 442 443 if (user_callb != NULL) { 444 user_callb(UPWR_SG_EXCEPT, msg->hdr.function, 445 (upwr_resp_t)msg->hdr.errcode, 446 (int)((sg_rsp_siz[UPWR_SG_EXCEPT] == 2U) ? 447 msg->word2 : msg->hdr.ret)); 448 } 449 } 450 break; 451 452 default: 453 break; 454 } 455 } 456 457 /** 458 * upwr_init() - API initialization; must be the first API call after reset. 459 * @domain: SoC-dependent CPU domain id; identifier used by the firmware in 460 * many services. Defined by SoC-dependent type soc_domain_t found in 461 * upower_soc_defs.h. 462 * @muptr: pointer to the MU instance. 463 * @mallocptr: pointer to the memory allocation function 464 * @physaddrptr: pointer to the function to convert pointers to 465 * physical addresses. If NULL, no conversion is made (pointer=physical address) 466 * @isrinstptr: pointer to the function to install the uPower ISR callbacks; 467 * the function receives the pointers to the MU tx/rx and Exception ISRs 468 * callbacks, which must be called from the actual system ISRs. 469 * The function pointed by isrinstptr must also enable the interrupt at the 470 * core/interrupt controller, but must not enable the interrupt at the MU IP. 471 * The system ISRs are responsible for dealing with the interrupt controller, 472 * performing any other context save/restore, and any other housekeeping. 473 * @lockptr: pointer to a function that prevents MU interrupts (if argrument=1) 474 * or allows it (if argument=0). The API calls this function to make small 475 * specific code portions thread safe. Only MU interrupts must be avoided, 476 * the code may be suspended for other reasons. 477 * If no MU interrupts can happen during the execution of an API call or 478 * callback, even if enabled, for some other reason (e.g. interrupt priority), 479 * then this argument may be NULL. 480 * 481 * Context: no sleep, no locks taken/released. 482 * Return: 0 if ok, 483 * -1 if failed to allocate memory, or use some other resource. 484 * -2 if any argument is invalid. 485 * -3 if failed to send the ping message. 486 * -4 if failed to receive the initialization message, or was invalid 487 */ 488 int upwr_init(soc_domain_t domain, struct MU_t *muptr, 489 const upwr_malloc_ptr_t mallocptr, 490 const upwr_phyadr_ptr_t phyadrptr, 491 const upwr_inst_isr_ptr_t isrinstptr, 492 const upwr_lock_ptr_t lockptr) 493 { 494 uint32_t j; 495 496 upwr_sg_t sg; /* service group number */ 497 unsigned int size; 498 unsigned long dom_buffer_base = (domain == RTD_DOMAIN) ? UPWR_API_BUFFER_BASE : 499 ((UPWR_API_BUFFER_ENDPLUS + UPWR_API_BUFFER_BASE) / 2U); 500 501 upwr_init_msg *msg = (upwr_init_msg *)&sg_rsp_msg[UPWR_SG_EXCEPT]; 502 503 mu = muptr; 504 /* 505 * Disable tx and rx interrupts in case not called 506 * 1st time after reset 507 */ 508 mu->TCR.R = mu->RCR.R = 0U; 509 510 os_malloc = mallocptr; 511 os_ptr2phy = (phyadrptr == (upwr_phyadr_ptr_t)NULL) ? ptr2phys : phyadrptr; 512 513 os_lock = lockptr; 514 api_state = UPWR_API_INIT_WAIT; 515 sg_busy = 0UL; 516 pwr_domain = domain; 517 518 /* initialize the versions, in case they are polled */ 519 fw_rom_version.soc_id = 0U; 520 fw_rom_version.vmajor = 0U; 521 fw_rom_version.vminor = 0U; 522 fw_rom_version.vfixes = 0U; 523 524 fw_ram_version.soc_id = 0U; 525 fw_ram_version.vmajor = 0U; 526 fw_ram_version.vminor = 0U; 527 fw_ram_version.vfixes = 0U; 528 529 mu_tx_pend = (uint32_t)0U; 530 sg_tx_pend = (uint32_t)0U; 531 532 sg_tx_curr = UPWR_SG_COUNT; /* means none here */ 533 534 sh_buffer[UPWR_SG_EXCEPT] = (void *)(unsigned long)dom_buffer_base; 535 sh_buffer[UPWR_SG_PWRMGMT] = (void *)(unsigned long)(dom_buffer_base + 536 MAX_SG_EXCEPT_MEM_SIZE); 537 sh_buffer[UPWR_SG_DELAYM] = NULL; 538 sh_buffer[UPWR_SG_VOLTM] = (void *)(unsigned long)(dom_buffer_base + 539 MAX_SG_EXCEPT_MEM_SIZE + MAX_SG_PWRMGMT_MEM_SIZE); 540 sh_buffer[UPWR_SG_CURRM] = NULL; 541 sh_buffer[UPWR_SG_TEMPM] = NULL; 542 sh_buffer[UPWR_SG_DIAG] = NULL; 543 544 /* (no buffers service groups other than xcp and pwm for now) */ 545 for (j = 0; j < UPWR_SG_COUNT; j++) { 546 user_callback[j] = NULL; 547 /* service group Exception gets the initialization callbacks */ 548 sgrp_callback[j] = (j == UPWR_SG_EXCEPT) ? upwr_start_callb : NULL; 549 /* response messages with an initial consistent content */ 550 sg_rsp_msg[j].hdr.errcode = UPWR_RESP_SHUTDOWN; 551 } 552 553 /* init message already received, assume takss are running on upower */ 554 if (mu->FSR.B.F0 != 0U) { 555 /* send a ping message down to get the ROM version back */ 556 upwr_xcp_ping_msg ping_msg = {0}; 557 558 ping_msg.hdr.domain = pwr_domain; 559 ping_msg.hdr.srvgrp = UPWR_SG_EXCEPT; 560 ping_msg.hdr.function = UPWR_XCP_PING; 561 562 if (mu->RSR.B.RF0 != 0U) { /* first clean any Rx message left over */ 563 (void)upwr_rx((char *)msg, &size); 564 } 565 566 /* wait any TX left over to be sent */ 567 while (mu->TSR.R != UPWR_MU_TSR_EMPTY) { 568 } 569 570 /* 571 * now send the ping message; 572 * do not use upwr_tx, which needs API initialized; 573 * just write to the MU TR register(s) 574 */ 575 mu->FCR.B.F0 = 1U; /* flag urgency status */ 576 upwr_copy2tr(mu, (uint32_t *)&ping_msg, sizeof(ping_msg) / 4U); 577 } 578 579 do { 580 /* 581 * poll for the MU Rx status: wait for an init message, either 582 * 1st sent from uPower after reset or as a response to a ping 583 */ 584 while (mu->RSR.B.RF0 == 0U) { 585 } 586 587 /* urgency status off, in case it was set */ 588 mu->FCR.B.F0 = 0U; 589 590 if (upwr_rx((char *)msg, &size) < 0) { 591 return -4; 592 } 593 594 if (size != (sizeof(upwr_init_msg) / 4U)) { 595 if (mu->FSR.B.F0 != 0U) { 596 continue; /* discard left over msg */ 597 } else { 598 return -4; 599 } 600 } 601 602 sg = (upwr_sg_t)msg->hdr.srvgrp; 603 if (sg != UPWR_SG_EXCEPT) { 604 if (mu->FSR.B.F0 != 0U) { 605 continue; /* discard left over msg */ 606 } else { 607 return -4; 608 } 609 } 610 611 if ((upwr_xcp_f_t)msg->hdr.function != UPWR_XCP_INIT) { 612 if (mu->FSR.B.F0 != 0U) { 613 continue; /* discard left over msg */ 614 } else { 615 return -4; 616 } 617 } 618 619 break; 620 } while (true); 621 622 fw_rom_version.soc_id = msg->args.soc; 623 fw_rom_version.vmajor = msg->args.vmajor; 624 fw_rom_version.vminor = msg->args.vminor; 625 fw_rom_version.vfixes = msg->args.vfixes; 626 627 if (upwr_rx_callback(upwr_mu_int_callback) < 0) { 628 /* catastrophic error, but is it possible to happen? */ 629 return -1; 630 } 631 632 mu_tx_callb = NULL; /* assigned on upwr_tx */ 633 634 /* install the ISRs and enable the interrupts */ 635 isrinstptr(upwr_txrx_isr, upwr_exp_isr); 636 637 /* enable only RR[0] receive interrupt */ 638 mu->RCR.R = 1U; 639 640 api_state = UPWR_API_INITLZED; 641 642 return 0; 643 } 644 645 /** 646 * upwr_start() - Starts the uPower services. 647 * @launchopt: a number to select between multiple launch options, 648 * that may define, among other things, which services will be started, 649 * or which services implementations, features etc. 650 * launchopt = 0 selects a subset of services implemented in ROM; 651 * any other number selects service sets implemented in RAM, launched 652 * by the firmware function ram_launch; if an invalid launchopt value is passed, 653 * no services are started, and the callback returns error (see below). 654 * @rdycallb: pointer to the callback to be called when the uPower is ready 655 * to receive service requests. NULL if no callback needed. 656 * The callback receives as arguments the RAM firmware version numbers. 657 * If all 3 numbers (vmajor, vminor, vfixes) are 0, that means the 658 * service launching failed. 659 * Firmware version numbers will be the same as ROM if launchopt = 0, 660 * selecting the ROM services. 661 * 662 * upwr_start can be called by any domain even if the services are already 663 * started: it has no effect, returning success, if the launch option is the 664 * same as the one that actually started the service, and returns error if 665 * called with a different option. 666 * 667 * A callback can be optionally registered, and will be called upon the arrival 668 * of the request response from the uPower firmware, telling if it succeeded or 669 * not. 670 * A callback may not be registered (NULL pointer), in which case polling has 671 * to be used to check the response, by calling upwr_req_status or 672 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 673 * 674 * Context: no sleep, no locks taken/released. 675 * Return: 0 if ok, 676 * -1 if a resource failed, 677 * -2 if the domain passed is the same as the caller, 678 * -3 if called in an invalid API state 679 */ 680 int upwr_start(uint32_t launchopt, const upwr_rdy_callb rdycallb) 681 { 682 upwr_start_msg txmsg = {0}; 683 684 if (api_state != UPWR_API_INITLZED) { 685 return -3; 686 } 687 688 UPWR_USR_CALLB(UPWR_SG_EXCEPT, (upwr_callb)rdycallb); 689 690 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_START); 691 692 txmsg.hdr.arg = fw_launch_option = launchopt; 693 694 if (upwr_tx((uint32_t *)&txmsg, sizeof(txmsg) / 4U, NULL) < 0) { 695 /* catastrophic error, but is it possible to happen? */ 696 return -1; 697 } 698 699 api_state = UPWR_API_START_WAIT; 700 701 return 0; 702 } 703 704 /**--------------------------------------------------------------- 705 * EXCEPTION SERVICE GROUP 706 */ 707 708 /** 709 * upwr_xcp_config() - Applies general uPower configurations. 710 * @config: pointer to the uPower SoC-dependent configuration struct 711 * upwr_xcp_config_t defined in upower_soc_defs.h. NULL may be passed, meaning 712 * a request to read the configuration, in which case it appears in the callback 713 * argument ret, or can be pointed by argument retptr in the upwr_req_status and 714 * upwr_poll_req_status calls, casted to upwr_xcp_config_t. 715 * @callb: pointer to the callback to be called when the uPower has finished 716 * the configuration, or NULL if no callback needed (polling used instead). 717 * 718 * Some configurations are targeted for a specific domain (see the struct 719 * upwr_xcp_config_t definition in upower_soc_defs.h); this call has implicit 720 * domain target (the same domain from which is called). 721 * 722 * The return value is always the current configuration value, either in a 723 * read-only request (config = NULL) or after setting a new configuration 724 * (non-NULL config). 725 * 726 * A callback can be optionally registered, and will be called upon the arrival 727 * of the request response from the uPower firmware, telling if it succeeded or 728 * not. 729 * A callback may not be registered (NULL pointer), in which case polling has 730 * to be used to check the response, by calling upwr_req_status or 731 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 732 * 733 * Context: no sleep, no locks taken/released. 734 * Return: 0 if ok, 735 * -1 if service group is busy, 736 * -3 if called in an invalid API state 737 */ 738 int upwr_xcp_config(const upwr_xcp_config_t *config, const upwr_callb callb) 739 { 740 upwr_xcp_config_msg txmsg = {0}; 741 742 if (api_state != UPWR_API_READY) { 743 return -3; 744 } 745 746 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 747 return -1; 748 } 749 750 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 751 752 if (config == NULL) { 753 txmsg.hdr.arg = 1U; /* 1= read, txmsg.word2 ignored */ 754 } else { 755 txmsg.hdr.arg = 0U; /* 1= write */ 756 txmsg.word2 = config->R; 757 } 758 759 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_CONFIG); 760 761 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 762 763 return 0; 764 } 765 766 /** 767 * upwr_xcp_sw_alarm() - Makes uPower issue an alarm interrupt to given domain. 768 * @domain: identifier of the domain to alarm. Defined by SoC-dependent type 769 * soc_domain_t found in upower_soc_defs.h. 770 * @code: alarm code. Defined by SoC-dependent type upwr_alarm_t found in 771 * upower_soc_defs.h. 772 * @callb: pointer to the callback to be called when the uPower has finished 773 * the alarm, or NULL if no callback needed (polling used instead). 774 * 775 * The function requests the uPower to issue an alarm of the given code as if 776 * it had originated internally. This service is useful mainly to test the 777 * system response to such alarms, or to make the system handle a similar alarm 778 * situation detected externally to uPower. 779 * 780 * The system ISR/code handling the alarm may retrieve the alarm code by calling 781 * the auxiliary function upwr_alarm_code. 782 * 783 * A callback can be optionally registered, and will be called upon the arrival 784 * of the request response from the uPower firmware, telling if it succeeded or 785 * not. 786 * A callback may not be registered (NULL pointer), in which case polling has 787 * to be used to check the response, by calling upwr_req_status or 788 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 789 * 790 * Context: no sleep, no locks taken/released. 791 * Return: 0 if ok, 792 * -1 if service group is busy, 793 * -3 if called in an invalid API state 794 */ 795 int upwr_xcp_sw_alarm(soc_domain_t domain, 796 upwr_alarm_t code, 797 const upwr_callb callb) 798 { 799 upwr_xcp_swalarm_msg txmsg = {0}; 800 801 if (api_state != UPWR_API_READY) { 802 return -3; 803 } 804 805 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 806 return -1; 807 } 808 809 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 810 811 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SW_ALARM); 812 txmsg.hdr.domain = (uint32_t)domain; 813 txmsg.hdr.arg = (uint32_t)code; 814 815 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 816 817 return 0; 818 } 819 820 /** 821 * upwr_xcp_set_ddr_retention() - M33/A35 can use this API to set/clear ddr retention 822 * @domain: identifier of the caller domain. 823 * soc_domain_t found in upower_soc_defs.h. 824 * @enable: true, means that set ddr retention, false clear ddr retention. 825 * @callb: NULL 826 * 827 * A callback may not be registered (NULL pointer), in which case polling has 828 * to be used to check the response, by calling upwr_req_status or 829 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 830 * 831 * Context: no sleep, no locks taken/released. 832 * Return: 0 if ok, 833 * -1 if service group is busy, 834 * -3 if called in an invalid API state 835 */ 836 int upwr_xcp_set_ddr_retention(soc_domain_t domain, 837 uint32_t enable, 838 const upwr_callb callb) 839 { 840 upwr_xcp_ddr_retn_msg txmsg = {0}; 841 842 if (api_state != UPWR_API_READY) { 843 return -3; 844 } 845 846 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 847 return -1; 848 } 849 850 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 851 852 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_DDR_RETN); 853 txmsg.hdr.domain = (uint32_t)domain; 854 txmsg.hdr.arg = (uint32_t)enable; 855 856 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 857 858 return 0; 859 } 860 861 /** 862 * upwr_xcp_set_mipi_dsi_ena() - M33/A35 can use this API to set/clear mipi dsi ena 863 * @domain: identifier of the caller domain. 864 * soc_domain_t found in upower_soc_defs.h. 865 * @enable: true, means that set ddr retention, false clear ddr retention. 866 * @callb: NULL 867 * 868 * A callback may not be registered (NULL pointer), in which case polling has 869 * to be used to check the response, by calling upwr_req_status or 870 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 871 * 872 * Context: no sleep, no locks taken/released. 873 * Return: 0 if ok, 874 * -1 if service group is busy, 875 * -3 if called in an invalid API state 876 */ 877 int upwr_xcp_set_mipi_dsi_ena(soc_domain_t domain, 878 uint32_t enable, 879 const upwr_callb callb) 880 { 881 upwr_xcp_set_mipi_dsi_ena_msg txmsg = {0}; 882 883 if (api_state != UPWR_API_READY) { 884 return -3; 885 } 886 887 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 888 return -1; 889 } 890 891 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 892 893 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_MIPI_DSI_ENA); 894 txmsg.hdr.domain = (uint32_t)domain; 895 txmsg.hdr.arg = (uint32_t)enable; 896 897 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 898 899 return 0; 900 } 901 902 /** 903 * upwr_xcp_get_mipi_dsi_ena() - M33/A35 can use this API to get mipi dsi ena status 904 * @domain: identifier of the caller domain. 905 * soc_domain_t found in upower_soc_defs.h. 906 * @callb: NULL 907 * 908 * A callback may not be registered (NULL pointer), in which case polling has 909 * to be used to check the response, by calling upwr_req_status or 910 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 911 * 912 * Context: no sleep, no locks taken/released. 913 * Return: 0 if ok, 914 * -1 if service group is busy, 915 * -3 if called in an invalid API state 916 */ 917 int upwr_xcp_get_mipi_dsi_ena(soc_domain_t domain, const upwr_callb callb) 918 { 919 upwr_xcp_get_mipi_dsi_ena_msg txmsg = {0}; 920 921 if (api_state != UPWR_API_READY) { 922 return -3; 923 } 924 925 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 926 return -1; 927 } 928 929 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 930 931 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_GET_MIPI_DSI_ENA); 932 txmsg.hdr.domain = (uint32_t)domain; 933 934 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 935 936 return 0; 937 } 938 939 /** 940 * upwr_xcp_set_osc_mode() - M33/A35 can use this API to set uPower OSC mode 941 * @domain: identifier of the caller domain. 942 * soc_domain_t found in upower_soc_defs.h. 943 * @osc_mode, 0 means low frequency, not 0 means high frequency. 944 * @callb: NULL 945 * 946 * A callback may not be registered (NULL pointer), in which case polling has 947 * to be used to check the response, by calling upwr_req_status or 948 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 949 * 950 * Context: no sleep, no locks taken/released. 951 * Return: 0 if ok, 952 * -1 if service group is busy, 953 * -3 if called in an invalid API state 954 */ 955 int upwr_xcp_set_osc_mode(soc_domain_t domain, 956 uint32_t osc_mode, 957 const upwr_callb callb) 958 { 959 upwr_xcp_set_osc_mode_msg txmsg = {0}; 960 961 if (api_state != UPWR_API_READY) { 962 return -3; 963 } 964 965 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 966 return -1; 967 } 968 969 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 970 971 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_OSC_MODE); 972 txmsg.hdr.domain = (uint32_t)domain; 973 txmsg.hdr.arg = (uint32_t)osc_mode; 974 975 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 976 977 return 0; 978 } 979 980 /** 981 * upwr_xcp_set_rtd_use_ddr() - M33 call this API to inform uPower, M33 is using ddr 982 * @domain: identifier of the caller domain. 983 * soc_domain_t found in upower_soc_defs.h. 984 * @is_use_ddr: not 0, true, means that RTD is using ddr. 0, false, means that, RTD 985 * is not using ddr. 986 * @callb: NULL 987 * 988 * A callback may not be registered (NULL pointer), in which case polling has 989 * to be used to check the response, by calling upwr_req_status or 990 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 991 * 992 * Context: no sleep, no locks taken/released. 993 * Return: 0 if ok, 994 * -1 if service group is busy, 995 * -3 if called in an invalid API state 996 */ 997 int upwr_xcp_set_rtd_use_ddr(soc_domain_t domain, 998 uint32_t is_use_ddr, 999 const upwr_callb callb) 1000 { 1001 upwr_xcp_rtd_use_ddr_msg txmsg = {0}; 1002 1003 if (api_state != UPWR_API_READY) { 1004 return -3; 1005 } 1006 1007 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 1008 return -1; 1009 } 1010 1011 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 1012 1013 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_RTD_USE_DDR); 1014 txmsg.hdr.domain = (uint32_t)domain; 1015 txmsg.hdr.arg = (uint32_t)is_use_ddr; 1016 1017 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1018 1019 return 0; 1020 } 1021 1022 /** 1023 * upwr_xcp_set_rtd_apd_llwu() - M33/A35 can use this API to set/clear rtd_llwu apd_llwu 1024 * @domain: set which domain (RTD_DOMAIN, APD_DOMAIN) LLWU. 1025 * soc_domain_t found in upower_soc_defs.h. 1026 * @enable: true, means that set rtd_llwu or apd_llwu, false clear rtd_llwu or apd_llwu. 1027 * @callb: NULL 1028 * 1029 * A callback may not be registered (NULL pointer), in which case polling has 1030 * to be used to check the response, by calling upwr_req_status or 1031 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 1032 * 1033 * Context: no sleep, no locks taken/released. 1034 * Return: 0 if ok, 1035 * -1 if service group is busy, 1036 * -3 if called in an invalid API state 1037 */ 1038 int upwr_xcp_set_rtd_apd_llwu(soc_domain_t domain, 1039 uint32_t enable, 1040 const upwr_callb callb) 1041 { 1042 upwr_xcp_rtd_apd_llwu_msg txmsg = {0}; 1043 1044 if (api_state != UPWR_API_READY) { 1045 return -3; 1046 } 1047 1048 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 1049 return -1; 1050 } 1051 1052 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 1053 1054 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SET_RTD_APD_LLWU); 1055 txmsg.hdr.domain = (uint32_t)domain; 1056 txmsg.hdr.arg = (uint32_t)enable; 1057 1058 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1059 1060 return 0; 1061 } 1062 1063 /** 1064 * upwr_xcp_shutdown() - Shuts down all uPower services and power mode tasks. 1065 * @callb: pointer to the callback to be called when the uPower has finished 1066 * the shutdown, or NULL if no callback needed 1067 * (polling used instead). 1068 * 1069 * A callback can be optionally registered, and will be called upon the arrival 1070 * of the request response from the uPower firmware, telling if it succeeded or 1071 * not. 1072 * A callback may not be registered (NULL pointer), in which case polling has 1073 * to be used to check the response, by calling upwr_req_status or 1074 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 1075 * 1076 * At the callback the uPower/API is back to initialization/start-up phase, 1077 * so service request calls return error. 1078 * 1079 * Context: no sleep, no locks taken/released. 1080 * Return: 0 if ok, 1081 * -1 if service group is busy, 1082 * -3 if called in an invalid API state 1083 */ 1084 int upwr_xcp_shutdown(const upwr_callb callb) 1085 { 1086 upwr_xcp_shutdown_msg txmsg = {0}; 1087 1088 if (api_state != UPWR_API_READY) { 1089 return -3; 1090 } 1091 1092 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 1093 return -1; 1094 } 1095 1096 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 1097 1098 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_SHUTDOWN); 1099 1100 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1101 1102 api_state = UPWR_API_SHUTDOWN_WAIT; 1103 1104 return 0; 1105 } 1106 1107 /** 1108 * upwr_xcp_i2c_access() - Performs an access through the uPower I2C interface. 1109 * @addr: I2C slave address, up to 10 bits. 1110 * @data_size: determines the access direction and data size in bytes, up to 4; 1111 * negetive data_size determines a read access with size -data_size; 1112 * positive data_size determines a write access with size data_size; 1113 * data_size=0 is invalid, making the service return error UPWR_RESP_BAD_REQ. 1114 * @subaddr_size: size of the sub-address in bytes, up to 4; if subaddr_size=0, 1115 * no subaddress is used. 1116 * @subaddr: sub-address, only used if subaddr_size > 0. 1117 * @wdata: write data, up to 4 bytes; ignored if data_size < 0 (read) 1118 * @callb: pointer to the callback to be called when the uPower has finished 1119 * the access, or NULL if no callback needed 1120 * (polling used instead). 1121 * 1122 * A callback can be optionally registered, and will be called upon the arrival 1123 * of the request response from the uPower firmware, telling if it succeeded or 1124 * not. 1125 * A callback may not be registered (NULL pointer), in which case polling has 1126 * to be used to check the response, by calling upwr_req_status or 1127 * upwr_poll_req_status, using UPWR_SG_EXCEPT as the service group argument. 1128 * 1129 * The service performs a read (data_size < 0) or a write (data_size > 0) of 1130 * up to 4 bytes on the uPower I2C interface. The data read from I2C comes via 1131 * the callback argument ret, or written to the variable pointed by retptr, 1132 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1133 * ret (or *retptr) also returns the data written on writes. 1134 * 1135 * Sub-addressing is supported, with sub-address size determined by the argument 1136 * subaddr_size, up to 4 bytes. Sub-addressing is not used if subaddr_size=0. 1137 * 1138 * Context: no sleep, no locks taken/released. 1139 * Return: 0 if ok, 1140 * -1 if service group is busy, 1141 * -3 if called in an invalid API state 1142 */ 1143 1144 int upwr_xcp_i2c_access(uint16_t addr, 1145 int8_t data_size, 1146 uint8_t subaddr_size, 1147 uint32_t subaddr, 1148 uint32_t wdata, 1149 const upwr_callb callb) 1150 { 1151 unsigned long ptrval = (unsigned long)sh_buffer[UPWR_SG_EXCEPT]; 1152 upwr_i2c_access *i2c_acc_ptr = (upwr_i2c_access *)ptrval; 1153 upwr_pwm_pmiccfg_msg txmsg = {0}; 1154 1155 if (api_state != UPWR_API_READY) { 1156 return -3; 1157 } 1158 1159 if (UPWR_SG_BUSY(UPWR_SG_EXCEPT)) { 1160 return -1; 1161 } 1162 1163 UPWR_USR_CALLB(UPWR_SG_EXCEPT, callb); 1164 1165 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_EXCEPT, UPWR_XCP_I2C); 1166 1167 i2c_acc_ptr->addr = addr; 1168 i2c_acc_ptr->subaddr = subaddr; 1169 i2c_acc_ptr->subaddr_size = subaddr_size; 1170 i2c_acc_ptr->data = wdata; 1171 i2c_acc_ptr->data_size = data_size; 1172 1173 txmsg.ptr = upwr_ptr2offset(ptrval, 1174 UPWR_SG_EXCEPT, 1175 (size_t)sizeof(upwr_i2c_access), 1176 0U, 1177 i2c_acc_ptr); 1178 1179 upwr_srv_req(UPWR_SG_EXCEPT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1180 1181 return 0; 1182 } 1183 1184 /**--------------------------------------------------------------- 1185 * VOLTAGE MANAGERMENT SERVICE GROUP 1186 */ 1187 1188 /** 1189 * upwr_vtm_pmic_cold_reset() -request cold reset the pmic. 1190 * pmic will power cycle all the regulators 1191 * @callb: response callback pointer; NULL if no callback needed. 1192 * 1193 * The function requests uPower to cold reset the pmic. 1194 * The request is executed if arguments are within range, with no protections 1195 * regarding the adequate voltage value for the given domain process, 1196 * temperature and frequency. 1197 * 1198 * A callback can be optionally registered, and will be called upon the arrival 1199 * of the request response from the uPower firmware, telling if it succeeded 1200 * or not. 1201 * 1202 * A callback may not be registered (NULL pointer), in which case polling has 1203 * to be used to check the response, by calling upwr_req_status or 1204 * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument. 1205 * 1206 * Context: no sleep, no locks taken/released. 1207 * Return: 0 if ok, 1208 * -1 if service group is busy, 1209 * -3 if called in an invalid API state 1210 * Note that this is not the error response from the request itself: 1211 * it only tells if the request was successfully sent to the uPower. 1212 */ 1213 int upwr_vtm_pmic_cold_reset(upwr_callb callb) 1214 { 1215 upwr_volt_pmic_cold_reset_msg txmsg = {0}; 1216 1217 if (api_state != UPWR_API_READY) { 1218 return -3; 1219 } 1220 1221 if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) { 1222 return -1; 1223 } 1224 1225 UPWR_USR_CALLB(UPWR_SG_VOLTM, callb); 1226 1227 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_PMIC_COLD_RESET); 1228 1229 upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1230 1231 return 0; 1232 } 1233 1234 /** 1235 * upwr_vtm_set_pmic_mode() -request uPower set pmic mode 1236 * @pmic_mode: the target mode need to be set 1237 * @callb: response callback pointer; NULL if no callback needed. 1238 * 1239 * The function requests uPower to set pmic mode 1240 * The request is executed if arguments are within range, with no protections 1241 * regarding the adequate voltage value for the given domain process, 1242 * temperature and frequency. 1243 * 1244 * A callback can be optionally registered, and will be called upon the arrival 1245 * of the request response from the uPower firmware, telling if it succeeded 1246 * or not. 1247 * 1248 * A callback may not be registered (NULL pointer), in which case polling has 1249 * to be used to check the response, by calling upwr_req_status or 1250 * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument. 1251 * 1252 * Context: no sleep, no locks taken/released. 1253 * Return: 0 if ok, 1254 * -1 if service group is busy, 1255 * -3 if called in an invalid API state 1256 * Note that this is not the error response from the request itself: 1257 * it only tells if the request was successfully sent to the uPower. 1258 */ 1259 int upwr_vtm_set_pmic_mode(uint32_t pmic_mode, upwr_callb callb) 1260 { 1261 upwr_volt_pmic_set_mode_msg txmsg = {0}; 1262 1263 if (api_state != UPWR_API_READY) { 1264 return -3; 1265 } 1266 1267 if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) { 1268 return -1; 1269 } 1270 1271 UPWR_USR_CALLB(UPWR_SG_VOLTM, callb); 1272 1273 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_SET_PMIC_MODE); 1274 1275 txmsg.hdr.arg = pmic_mode; 1276 1277 upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1278 1279 return 0; 1280 } 1281 1282 /** 1283 * upwr_vtm_chng_pmic_voltage() - Changes the voltage of a given rail. 1284 * @rail: pmic rail id. 1285 * @volt: the target voltage of the given rail, accurate to uV 1286 * If pass volt value 0, means that power off this rail. 1287 * @callb: response callback pointer; NULL if no callback needed. 1288 * 1289 * The function requests uPower to change the voltage of the given rail. 1290 * The request is executed if arguments are within range, with no protections 1291 * regarding the adequate voltage value for the given domain process, 1292 * temperature and frequency. 1293 * 1294 * A callback can be optionally registered, and will be called upon the arrival 1295 * of the request response from the uPower firmware, telling if it succeeded 1296 * or not. 1297 * 1298 * A callback may not be registered (NULL pointer), in which case polling has 1299 * to be used to check the response, by calling upwr_req_status or 1300 * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument. 1301 * 1302 * Context: no sleep, no locks taken/released. 1303 * Return: 0 if ok, 1304 * -1 if service group is busy, 1305 * -3 if called in an invalid API state 1306 * Note that this is not the error response from the request itself: 1307 * it only tells if the request was successfully sent to the uPower. 1308 */ 1309 int upwr_vtm_chng_pmic_voltage(uint32_t rail, uint32_t volt, upwr_callb callb) 1310 { 1311 upwr_volt_pmic_set_volt_msg txmsg = {0}; 1312 1313 if (api_state != UPWR_API_READY) { 1314 return -3; 1315 } 1316 1317 if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) { 1318 return -1; 1319 } 1320 1321 UPWR_USR_CALLB(UPWR_SG_VOLTM, callb); 1322 1323 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_CHNG_PMIC_RAIL_VOLT); 1324 1325 txmsg.args.rail = rail; 1326 1327 txmsg.args.volt = (volt + PMIC_VOLTAGE_MIN_STEP - 1U) / PMIC_VOLTAGE_MIN_STEP; 1328 1329 upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1330 1331 return 0; 1332 } 1333 1334 /** 1335 * upwr_vtm_get_pmic_voltage() - Get the voltage of a given rail. 1336 * @rail: pmic rail id. 1337 * @callb: response callback pointer; NULL if no callback needed. 1338 * (polling used instead) 1339 * 1340 * The function requests uPower to get the voltage of the given rail. 1341 * The request is executed if arguments are within range, with no protections 1342 * regarding the adequate voltage value for the given domain process, 1343 * temperature and frequency. 1344 * 1345 * A callback can be optionally registered, and will be called upon the arrival 1346 * of the request response from the uPower firmware, telling if it succeeded 1347 * or not. 1348 * 1349 * A callback may not be registered (NULL pointer), in which case polling has 1350 * to be used to check the response, by calling upwr_req_status or 1351 * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument. 1352 * 1353 * The voltage data read from uPower via 1354 * the callback argument ret, or written to the variable pointed by retptr, 1355 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1356 * ret (or *retptr) also returns the data written on writes. 1357 * 1358 * Context: no sleep, no locks taken/released. 1359 * Return: 0 if ok, 1360 * -1 if service group is busy, 1361 * -3 if called in an invalid API state 1362 * Note that this is not the error response from the request itself: 1363 * it only tells if the request was successfully sent to the uPower. 1364 */ 1365 int upwr_vtm_get_pmic_voltage(uint32_t rail, upwr_callb callb) 1366 { 1367 upwr_volt_pmic_get_volt_msg txmsg = {0}; 1368 1369 if (api_state != UPWR_API_READY) { 1370 return -3; 1371 } 1372 1373 if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) { 1374 return -1; 1375 } 1376 1377 UPWR_USR_CALLB(UPWR_SG_VOLTM, callb); 1378 1379 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_GET_PMIC_RAIL_VOLT); 1380 1381 txmsg.args.rail = rail; 1382 1383 upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1384 1385 return 0; 1386 } 1387 1388 /** 1389 * upwr_vtm_power_measure() - request uPower to measure power consumption 1390 * @ssel: This field determines which power switches will have their currents 1391 * sampled to be accounted for a 1392 * current/power measurement. Support 0~7 1393 1394 * SSEL bit # Power Switch 1395 * 0 M33 core complex/platform/peripherals 1396 * 1 Fusion Core and Peripherals 1397 * 2 A35[0] core complex 1398 * 3 A35[1] core complex 1399 * 4 3DGPU 1400 * 5 HiFi4 1401 * 6 DDR Controller (PHY and PLL NOT included) 1402 * 7 PXP, EPDC 1403 * 1404 * @callb: response callback pointer; NULL if no callback needed. 1405 * (polling used instead) 1406 * 1407 * The function requests uPower to measure power consumption 1408 * The request is executed if arguments are within range, with no protections 1409 * regarding the adequate voltage value for the given domain process, 1410 * temperature and frequency. 1411 * 1412 * A callback can be optionally registered, and will be called upon the arrival 1413 * of the request response from the uPower firmware, telling if it succeeded 1414 * or not. 1415 * 1416 * A callback may not be registered (NULL pointer), in which case polling has 1417 * to be used to check the response, by calling upwr_req_status or 1418 * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument. 1419 * 1420 * The power consumption data read from uPower via 1421 * the callback argument ret, or written to the variable pointed by retptr, 1422 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1423 * ret (or *retptr) also returns the data written on writes. 1424 * upower fw needs support cocurrent request from M33 and A35. 1425 * 1426 * Accurate to uA 1427 * 1428 * Context: no sleep, no locks taken/released. 1429 * Return: 0 if ok, 1430 * -1 if service group is busy, 1431 * -3 if called in an invalid API state 1432 * Note that this is not the error response from the request itself: 1433 * it only tells if the request was successfully sent to the uPower. 1434 */ 1435 int upwr_vtm_power_measure(uint32_t ssel, upwr_callb callb) 1436 { 1437 upwr_volt_pmeter_meas_msg txmsg = {0}; 1438 1439 if (api_state != UPWR_API_READY) { 1440 return -3; 1441 } 1442 1443 if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) { 1444 return -1; 1445 } 1446 1447 UPWR_USR_CALLB(UPWR_SG_VOLTM, callb); 1448 1449 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_PMETER_MEAS); 1450 1451 txmsg.hdr.arg = ssel; 1452 1453 upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1454 1455 return 0; 1456 } 1457 1458 /** 1459 * upwr_vtm_vmeter_measure() - request uPower to measure voltage 1460 * @vdetsel: Voltage Detector Selector, support 0~3 1461 * 00b - RTD sense point 1462 01b - LDO output 1463 10b - APD domain sense point 1464 11b - AVD domain sense point 1465 Refer to upower_defs.h 1466 * @callb: response callback pointer; NULL if no callback needed. 1467 * (polling used instead) 1468 * 1469 * The function requests uPower to use vmeter to measure voltage 1470 * The request is executed if arguments are within range, with no protections 1471 * regarding the adequate voltage value for the given domain process, 1472 * temperature and frequency. 1473 * 1474 * A callback can be optionally registered, and will be called upon the arrival 1475 * of the request response from the uPower firmware, telling if it succeeded 1476 * or not. 1477 * 1478 * A callback may not be registered (NULL pointer), in which case polling has 1479 * to be used to check the response, by calling upwr_req_status or 1480 * upwr_poll_req_status, using UPWR_SG_VOLTM as the service group argument. 1481 * 1482 * The voltage data read from uPower via 1483 * the callback argument ret, or written to the variable pointed by retptr, 1484 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1485 * ret (or *retptr) also returns the data written on writes. 1486 * upower fw needs support cocurrent request from M33 and A35. 1487 * 1488 * Refer to RM COREREGVL (Core Regulator Voltage Level) 1489 * uPower return VDETLVL to user, user can calculate the real voltage: 1490 * 1491 0b000000(0x00) - 0.595833V 1492 0b100110(0x26) - 1.007498V 1493 <value> - 0.595833V + <value>x10.8333mV 1494 0b110010(0x32) - 1.138V 1495 * 1496 * Context: no sleep, no locks taken/released. 1497 * Return: 0 if ok, 1498 * -1 if service group is busy, 1499 * -3 if called in an invalid API state 1500 * Note that this is not the error response from the request itself: 1501 * it only tells if the request was successfully sent to the uPower. 1502 */ 1503 int upwr_vtm_vmeter_measure(uint32_t vdetsel, upwr_callb callb) 1504 { 1505 upwr_volt_vmeter_meas_msg txmsg = {0}; 1506 1507 if (api_state != UPWR_API_READY) { 1508 return -3; 1509 } 1510 1511 if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) { 1512 return -1; 1513 } 1514 1515 UPWR_USR_CALLB(UPWR_SG_VOLTM, callb); 1516 1517 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_VMETER_MEAS); 1518 1519 txmsg.hdr.arg = vdetsel; 1520 1521 upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1522 1523 return 0; 1524 } 1525 1526 /** 1527 * upwr_vtm_pmic_config() - Configures the SoC PMIC (Power Management IC). 1528 * @config: pointer to a PMIC-dependent struct defining the PMIC configuration. 1529 * @size: size of the struct pointed by config, in bytes. 1530 * @callb: pointer to the callback called when configurations are applied. 1531 * NULL if no callback is required. 1532 * 1533 * The function requests uPower to change/define the PMIC configuration. 1534 * 1535 * A callback can be optionally registered, and will be called upon the arrival 1536 * of the request response from the uPower firmware, telling if it succeeded 1537 * or not. 1538 * 1539 * A callback may not be registered (NULL pointer), in which case polling has 1540 * to be used to check the response, by calling upwr_req_status or 1541 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 1542 * 1543 * Context: no sleep, no locks taken/released. 1544 * Return: 0 if ok, -1 if service group is busy, 1545 * -2 if the pointer conversion to physical address failed, 1546 * -3 if called in an invalid API state. 1547 * Note that this is not the error response from the request itself: 1548 * it only tells if the request was successfully sent to the uPower. 1549 */ 1550 int upwr_vtm_pmic_config(const void *config, uint32_t size, upwr_callb callb) 1551 { 1552 upwr_pwm_pmiccfg_msg txmsg = {0}; 1553 unsigned long ptrval = 0UL; /* needed for X86, ARM64 */ 1554 1555 if (api_state != UPWR_API_READY) { 1556 return -3; 1557 } 1558 1559 if (UPWR_SG_BUSY(UPWR_SG_VOLTM)) { 1560 return -1; 1561 } 1562 1563 UPWR_USR_CALLB(UPWR_SG_VOLTM, callb); 1564 1565 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_VOLTM, UPWR_VTM_PMIC_CONFIG); 1566 1567 ptrval = (unsigned long)os_ptr2phy(config); 1568 if (ptrval == 0UL) { 1569 return -2; /* pointer conversion failed */ 1570 } 1571 1572 txmsg.ptr = upwr_ptr2offset(ptrval, 1573 UPWR_SG_VOLTM, 1574 (size_t)size, 1575 0U, 1576 config); 1577 1578 upwr_srv_req(UPWR_SG_VOLTM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1579 1580 return 0; 1581 } 1582 1583 /**--------------------------------------------------------------- 1584 * TEMPERATURE MANAGEMENT SERVICE GROUP 1585 */ 1586 1587 /** 1588 * upwr_tpm_get_temperature() - request uPower to get temperature of one temperature sensor 1589 * @sensor_id: temperature sensor ID, support 0~2 1590 * @callb: response callback pointer; NULL if no callback needed. 1591 * (polling used instead) 1592 * 1593 * The function requests uPower to measure temperature 1594 * The request is executed if arguments are within range, with no protections 1595 * regarding the adequate voltage value for the given domain process, 1596 * temperature and frequency. 1597 * 1598 * A callback can be optionally registered, and will be called upon the arrival 1599 * of the request response from the uPower firmware, telling if it succeeded 1600 * or not. 1601 * 1602 * A callback may not be registered (NULL pointer), in which case polling has 1603 * to be used to check the response, by calling upwr_req_status or 1604 * upwr_poll_req_status, using UPWR_SG_TEMPM as the service group argument. 1605 * 1606 * The temperature data read from uPower via 1607 * the callback argument ret, or written to the variable pointed by retptr, 1608 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1609 * ret (or *retptr) also returns the data written on writes. 1610 * 1611 * uPower return TSEL to the caller (M33 or A35), caller calculate the real temperature 1612 * Tsh = 0.000002673049*TSEL[7:0]^3 + 0.0003734262*TSEL[7:0]^2 + 1613 0.4487042*TSEL[7:0] - 46.98694 1614 * 1615 * upower fw needs support cocurrent request from M33 and A35. 1616 * 1617 * Context: no sleep, no locks taken/released. 1618 * Return: 0 if ok, 1619 * -1 if service group is busy, 1620 * -3 if called in an invalid API state 1621 * Note that this is not the error response from the request itself: 1622 * it only tells if the request was successfully sent to the uPower. 1623 */ 1624 int upwr_tpm_get_temperature(uint32_t sensor_id, upwr_callb callb) 1625 { 1626 upwr_temp_get_cur_temp_msg txmsg = {0}; 1627 1628 if (api_state != UPWR_API_READY) { 1629 return -3; 1630 } 1631 1632 if (UPWR_SG_BUSY(UPWR_SG_TEMPM)) { 1633 return -1; 1634 } 1635 1636 UPWR_USR_CALLB(UPWR_SG_TEMPM, callb); 1637 1638 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_TEMPM, UPWR_TEMP_GET_CUR_TEMP); 1639 1640 txmsg.args.sensor_id = sensor_id; 1641 1642 upwr_srv_req(UPWR_SG_TEMPM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1643 1644 return 0; 1645 } 1646 1647 /**--------------------------------------------------------------- 1648 * DELAY MANAGEMENT SERVICE GROUP 1649 */ 1650 1651 /** 1652 * upwr_dlm_get_delay_margin() - request uPower to get delay margin 1653 * @path: The critical path 1654 * @index: Use whitch delay meter 1655 * @callb: response callback pointer; NULL if no callback needed. 1656 * (polling used instead) 1657 * 1658 * The function requests uPower to get delay margin 1659 * The request is executed if arguments are within range, with no protections 1660 * regarding the adequate voltage value for the given domain process, 1661 * temperature and frequency. 1662 * 1663 * A callback can be optionally registered, and will be called upon the arrival 1664 * of the request response from the uPower firmware, telling if it succeeded 1665 * or not. 1666 * 1667 * A callback may not be registered (NULL pointer), in which case polling has 1668 * to be used to check the response, by calling upwr_req_status or 1669 * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument. 1670 * 1671 * The delay margin data read from uPower via 1672 * the callback argument ret, or written to the variable pointed by retptr, 1673 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1674 * ret (or *retptr) also returns the data written on writes. 1675 * upower fw needs support cocurrent request from M33 and A35. 1676 * 1677 * Context: no sleep, no locks taken/released. 1678 * Return: 0 if ok, 1679 * -1 if service group is busy, 1680 * -3 if called in an invalid API state 1681 * Note that this is not the error response from the request itself: 1682 * it only tells if the request was successfully sent to the uPower. 1683 */ 1684 int upwr_dlm_get_delay_margin(uint32_t path, uint32_t index, upwr_callb callb) 1685 { 1686 upwr_dmeter_get_delay_margin_msg txmsg = {0}; 1687 1688 if (api_state != UPWR_API_READY) { 1689 return -3; 1690 } 1691 1692 if (UPWR_SG_BUSY(UPWR_SG_DELAYM)) { 1693 return -1; 1694 } 1695 1696 UPWR_USR_CALLB(UPWR_SG_DELAYM, callb); 1697 1698 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DELAYM, UPWR_DMETER_GET_DELAY_MARGIN); 1699 1700 txmsg.args.path = path; 1701 txmsg.args.index = index; 1702 1703 upwr_srv_req(UPWR_SG_DELAYM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1704 1705 return 0; 1706 } 1707 1708 /** 1709 * upwr_dlm_set_delay_margin() - request uPower to set delay margin 1710 * @path: The critical path 1711 * @index: Use whitch delay meter 1712 * @delay_margin: the value of delay margin 1713 * @callb: response callback pointer; NULL if no callback needed. 1714 * (polling used instead) 1715 * 1716 * The function requests uPower to set delay margin 1717 * The request is executed if arguments are within range, with no protections 1718 * regarding the adequate voltage value for the given domain process, 1719 * temperature and frequency. 1720 * 1721 * A callback can be optionally registered, and will be called upon the arrival 1722 * of the request response from the uPower firmware, telling if it succeeded 1723 * or not. 1724 * 1725 * A callback may not be registered (NULL pointer), in which case polling has 1726 * to be used to check the response, by calling upwr_req_status or 1727 * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument. 1728 * 1729 * The result of the corresponding critical path, failed or not read from uPower via 1730 * the callback argument ret, or written to the variable pointed by retptr, 1731 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1732 * ret (or *retptr) also returns the data written on writes. 1733 * upower fw needs support cocurrent request from M33 and A35. 1734 * 1735 * Context: no sleep, no locks taken/released. 1736 * Return: 0 if ok, 1737 * -1 if service group is busy, 1738 * -3 if called in an invalid API state 1739 * Note that this is not the error response from the request itself: 1740 * it only tells if the request was successfully sent to the uPower. 1741 */ 1742 int upwr_dlm_set_delay_margin(uint32_t path, uint32_t index, uint32_t delay_margin, 1743 upwr_callb callb) 1744 { 1745 upwr_dmeter_set_delay_margin_msg txmsg = {0}; 1746 1747 if (api_state != UPWR_API_READY) { 1748 return -3; 1749 } 1750 1751 if (UPWR_SG_BUSY(UPWR_SG_DELAYM)) { 1752 return -1; 1753 } 1754 1755 UPWR_USR_CALLB(UPWR_SG_DELAYM, callb); 1756 1757 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DELAYM, UPWR_DMETER_SET_DELAY_MARGIN); 1758 1759 txmsg.args.path = path; 1760 txmsg.args.index = index; 1761 txmsg.args.dm = delay_margin; 1762 1763 upwr_srv_req(UPWR_SG_DELAYM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1764 1765 return 0; 1766 } 1767 1768 /** 1769 * upwr_dlm_process_monitor() - request uPower to do process monitor 1770 * @chain_sel: Chain Cell Type Selection 1771 * Select the chain to be used for the clock signal generation. 1772 * Support two types chain cell, 0~1 1773 0b - P4 type delay cells selected 1774 1b - P16 type delay cells selected 1775 * @callb: response callback pointer; NULL if no callback needed. 1776 * (polling used instead) 1777 * 1778 * The function requests uPower to do process monitor 1779 * The request is executed if arguments are within range, with no protections 1780 * regarding the adequate voltage value for the given domain process, 1781 * temperature and frequency. 1782 * 1783 * A callback can be optionally registered, and will be called upon the arrival 1784 * of the request response from the uPower firmware, telling if it succeeded 1785 * or not. 1786 * 1787 * A callback may not be registered (NULL pointer), in which case polling has 1788 * to be used to check the response, by calling upwr_req_status or 1789 * upwr_poll_req_status, using UPWR_SG_DELAYM as the service group argument. 1790 * 1791 * The result of process monitor, failed or not read from uPower via 1792 * the callback argument ret, or written to the variable pointed by retptr, 1793 * if polling is used (calls upwr_req_status or upwr_poll_req_status). 1794 * ret (or *retptr) also returns the data written on writes. 1795 * upower fw needs support cocurrent request from M33 and A35. 1796 * 1797 * Context: no sleep, no locks taken/released. 1798 * Return: 0 if ok, 1799 * -1 if service group is busy, 1800 * -3 if called in an invalid API state 1801 * Note that this is not the error response from the request itself: 1802 * it only tells if the request was successfully sent to the uPower. 1803 */ 1804 int upwr_dlm_process_monitor(uint32_t chain_sel, upwr_callb callb) 1805 { 1806 upwr_pmon_msg txmsg = {0}; 1807 1808 if (api_state != UPWR_API_READY) { 1809 return -3; 1810 } 1811 1812 if (UPWR_SG_BUSY(UPWR_SG_DELAYM)) { 1813 return -1; 1814 } 1815 1816 UPWR_USR_CALLB(UPWR_SG_DELAYM, callb); 1817 1818 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DELAYM, UPWR_PMON_REQ); 1819 1820 txmsg.args.chain_sel = chain_sel; 1821 1822 upwr_srv_req(UPWR_SG_DELAYM, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1823 1824 return 0; 1825 } 1826 1827 /**--------------------------------------------------------------- 1828 * POWER MANAGEMENT SERVICE GROUP 1829 */ 1830 1831 /** 1832 * upwr_pwm_dom_power_on() - Commands uPower to power on the platform of other 1833 * domain (not necessarily its core(s)); does not release the core reset. 1834 * @domain: identifier of the domain to power on. Defined by SoC-dependent type 1835 * soc_domain_t found in upower_soc_defs.h. 1836 * @boot_start: must be 1 to start the domain core(s) boot(s), releasing 1837 * its (their) resets, or 0 otherwise. 1838 * @pwroncallb: pointer to the callback to be called when the uPower has 1839 * finished the power on procedure, or NULL if no callback needed 1840 * (polling used instead). 1841 * 1842 * A callback can be optionally registered, and will be called upon the arrival 1843 * of the request response from the uPower firmware, telling if it succeeded or 1844 * not. 1845 * A callback may not be registered (NULL pointer), in which case polling has 1846 * to be used to check the response, by calling upwr_req_status or 1847 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 1848 * 1849 * Context: no sleep, no locks taken/released. 1850 * Return: 0 if ok, 1851 * -1 if service group is busy, 1852 * -2 if the domain passed is the same as the caller, 1853 * -3 if called in an invalid API state 1854 */ 1855 int upwr_pwm_dom_power_on(soc_domain_t domain, 1856 int boot_start, 1857 const upwr_callb pwroncallb) 1858 { 1859 upwr_pwm_dom_pwron_msg txmsg = {0}; 1860 1861 if (pwr_domain == domain) { 1862 return -2; 1863 } 1864 1865 if (api_state != UPWR_API_READY) { 1866 return -3; 1867 } 1868 1869 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 1870 return -1; 1871 } 1872 1873 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, (upwr_callb)pwroncallb); 1874 1875 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_DOM_PWRON); 1876 txmsg.hdr.domain = (uint32_t)domain; 1877 txmsg.hdr.arg = (uint32_t)boot_start; 1878 1879 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1880 1881 return 0; 1882 } 1883 1884 /** 1885 * upwr_pwm_boot_start() - Commands uPower to release the reset of other CPU(s), 1886 * starting their boots. 1887 * @domain: identifier of the domain to release the reset. Defined by 1888 * SoC-dependent type soc_domain_t found in upower_soc_defs.h. 1889 * @bootcallb: pointer to the callback to be called when the uPower has finished 1890 * the boot start procedure, or NULL if no callback needed 1891 * (polling used instead). 1892 * 1893 * A callback can be optionally registered, and will be called upon the arrival 1894 * of the request response from the uPower firmware, telling if it succeeded or 1895 * not. 1896 * A callback may not be registered (NULL pointer), in which case polling has 1897 * to be used to check the response, by calling upwr_req_status or 1898 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 1899 * 1900 * The callback calling doesn't mean the CPUs boots have finished: 1901 * it only indicates that uPower released the CPUs resets, and can receive 1902 * other power management service group requests. 1903 * 1904 * Context: no sleep, no locks taken/released. 1905 * Return: 0 if ok, 1906 * -1 if service group is busy, 1907 * -2 if the domain passed is the same as the caller, 1908 * -3 if called in an invalid API state 1909 */ 1910 int upwr_pwm_boot_start(soc_domain_t domain, const upwr_callb bootcallb) 1911 { 1912 upwr_pwm_boot_start_msg txmsg = {0}; 1913 1914 if (pwr_domain == domain) { 1915 return -2; 1916 } 1917 1918 if (api_state != UPWR_API_READY) { 1919 return -3; 1920 } 1921 1922 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 1923 return -1; 1924 } 1925 1926 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, (upwr_callb)bootcallb); 1927 1928 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_BOOT); 1929 txmsg.hdr.domain = (uint32_t)domain; 1930 1931 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1932 1933 return 0; 1934 } 1935 1936 /** 1937 * upwr_pwm_param() - Changes Power Management parameters. 1938 * @param: pointer to a parameter structure upwr_pwm_param_t, SoC-dependent, 1939 * defined in upwr_soc_defines.h. NULL may be passed, meaning 1940 * a request to read the parameter set, in which case it appears in the callback 1941 * argument ret, or can be pointed by argument retptr in the upwr_req_status and 1942 * upwr_poll_req_status calls, casted to upwr_pwm_param_t. 1943 * @callb: response callback pointer; NULL if no callback needed. 1944 * 1945 * The return value is always the current parameter set value, either in a 1946 * read-only request (param = NULL) or after setting a new parameter 1947 * (non-NULL param). 1948 * 1949 * Some parameters may be targeted for a specific domain (see the struct 1950 * upwr_pwm_param_t definition in upower_soc_defs.h); this call has implicit 1951 * domain target (the same domain from which is called). 1952 * 1953 * A callback can be optionally registered, and will be called upon the arrival 1954 * of the request response from the uPower firmware, telling if it succeeded or 1955 * not. 1956 * A callback may not be registered (NULL pointer), in which case polling has 1957 * to be used to check the response, by calling upwr_req_status or 1958 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 1959 * 1960 * Context: no sleep, no locks taken/released. 1961 * Return: 0 if ok, 1962 * -1 if service group is busy, 1963 * -3 if called in an invalid API state 1964 */ 1965 int upwr_pwm_param(upwr_pwm_param_t *param, const upwr_callb callb) 1966 { 1967 upwr_pwm_param_msg txmsg = {0}; 1968 1969 if (api_state != UPWR_API_READY) { 1970 return -3; 1971 } 1972 1973 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 1974 return -1; 1975 } 1976 1977 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 1978 1979 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_PARAM); 1980 1981 if (param == NULL) { 1982 txmsg.hdr.arg = 1U; /* 1= read, txmsg.word2 ignored */ 1983 } else { 1984 txmsg.hdr.arg = 0U; /* 1= write */ 1985 txmsg.word2 = param->R; /* just 1 word, so that's ok */ 1986 } 1987 1988 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 1989 1990 return 0; 1991 } 1992 1993 /** 1994 * upwr_pwm_chng_reg_voltage() - Changes the voltage at a given regulator. 1995 * @reg: regulator id. 1996 * @volt: voltage value; value unit is SoC-dependent, converted from mV by the 1997 * macro UPWR_VTM_MILIV, or from micro-Volts by the macro UPWR_VTM_MICROV, 1998 * both macros in upower_soc_defs.h 1999 * @callb: response callback pointer; NULL if no callback needed. 2000 * 2001 * The function requests uPower to change the voltage of the given regulator. 2002 * The request is executed if arguments are within range, with no protections 2003 * regarding the adequate voltage value for the given domain process, 2004 * temperature and frequency. 2005 * 2006 * A callback can be optionally registered, and will be called upon the arrival 2007 * of the request response from the uPower firmware, telling if it succeeded 2008 * or not. 2009 * 2010 * A callback may not be registered (NULL pointer), in which case polling has 2011 * to be used to check the response, by calling upwr_req_status or 2012 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2013 * 2014 * Context: no sleep, no locks taken/released. 2015 * Return: 0 if ok, 2016 * -1 if service group is busy, 2017 * -3 if called in an invalid API state 2018 * Note that this is not the error response from the request itself: 2019 * it only tells if the request was successfully sent to the uPower. 2020 */ 2021 int upwr_pwm_chng_reg_voltage(uint32_t reg, uint32_t volt, upwr_callb callb) 2022 { 2023 upwr_pwm_volt_msg txmsg = {0}; 2024 2025 if (api_state != UPWR_API_READY) { 2026 return -3; 2027 } 2028 2029 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2030 return -1; 2031 } 2032 2033 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2034 2035 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_VOLT); 2036 2037 txmsg.args.reg = reg; 2038 txmsg.args.volt = volt; 2039 2040 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2041 2042 return 0; 2043 } 2044 2045 /** 2046 * upwr_pwm_freq_setup() - Determines the next frequency target for a given 2047 * domain and current frequency. 2048 * @domain: identifier of the domain to change frequency. Defined by 2049 * SoC-dependent type soc_domain_t found in upower_soc_defs.h. 2050 * @rail: the pmic regulator number for the target domain. 2051 * @stage: DVA adjust stage 2052 * refer to upower_defs.h "DVA adjust stage" 2053 * @target_freq: the target adjust frequency, accurate to MHz 2054 * 2055 * refer to upower_defs.h structure definition upwr_pwm_freq_msg 2056 * 2057 * @callb: response callback pointer; NULL if no callback needed. 2058 * 2059 * The DVA algorithm is broken down into two phases. 2060 * The first phase uses a look up table to get a safe operating voltage 2061 * for the requested frequency. 2062 * This voltage is guaranteed to work over process and temperature. 2063 * 2064 * The second step of the second phase is to measure the temperature 2065 * using the uPower Temperature Sensor module. 2066 * This is accomplished by doing a binary search of the TSEL bit field 2067 * in the Temperature Measurement Register (TMR). 2068 * The search is repeated until the THIGH bit fields in the same register change value. 2069 * There are 3 temperature sensors in 8ULP (APD, AVD, and RTD). 2070 * 2071 * 2072 * The second phase is the fine adjust of the voltage. 2073 * This stage is entered only when the new frequency requested 2074 * by application was already set as well as the voltage for that frequency. 2075 * The first step of the fine adjust is to find what is the current margins 2076 * for the monitored critical paths, or, in other words, 2077 * how many delay cells will be necessary to generate a setup-timing violation. 2078 * The function informs uPower that the given domain frequency has changed or 2079 * will change to the given value. uPower firmware will then adjust voltage and 2080 * bias to cope with the new frequency (if decreasing) or prepare for it 2081 * (if increasing). The function must be called after decreasing the frequency, 2082 * and before increasing it. The actual increase in frequency must not occur 2083 * before the service returns its response. 2084 * 2085 * So, for increase clock frequency case, user need to call this API twice, 2086 * the first stage gross adjust and the second stage fine adjust. 2087 * 2088 * for reduce clock frequency case, user can only call this API once, 2089 * full stage (combine gross stage and fine adjust) 2090 * 2091 * The request is executed if arguments are within range. 2092 * 2093 * A callback can be optionally registered, and will be called upon the arrival 2094 * of the request response from the uPower firmware, telling if it succeeded 2095 * or not. 2096 * 2097 * A callback may not be registered (NULL pointer), in which case polling has 2098 * to be used to check the response, by calling upwr_req_status or 2099 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2100 * 2101 * Context: no sleep, no locks taken/released. 2102 * Return: 0 if ok, 2103 * -1 if service group is busy, 2104 * -3 if called in an invalid API state 2105 * Note that this is not the error response from the request itself: 2106 * it only tells if the request was successfully sent to the uPower. 2107 */ 2108 int upwr_pwm_freq_setup(soc_domain_t domain, uint32_t rail, uint32_t stage, uint32_t target_freq, 2109 upwr_callb callb) 2110 { 2111 upwr_pwm_freq_msg txmsg = {0}; 2112 2113 if (api_state != UPWR_API_READY) { 2114 return -3; 2115 } 2116 2117 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2118 return -1; 2119 } 2120 2121 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2122 2123 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_FREQ); 2124 2125 txmsg.hdr.domain = (uint32_t)domain; 2126 txmsg.args.rail = rail; 2127 txmsg.args.stage = stage; 2128 txmsg.args.target_freq = target_freq; 2129 2130 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2131 2132 return 0; 2133 } 2134 2135 /** 2136 * upwr_pwm_power_on()- Powers on (not off) one or more switches and ROM/RAMs. 2137 * @swton: pointer to an array of words that tells which power switches to 2138 * turn on. Each word in the array has 1 bit for each switch. 2139 * A bit=1 means the respective switch must be turned on, 2140 * bit = 0 means it will stay unchanged (on or off). 2141 * The pointer may be set to NULL, in which case no switch will be changed, 2142 * unless a memory that it feeds must be turned on. 2143 * WARNING: swton must not point to the first shared memory address. 2144 * @memon: pointer to an array of words that tells which memories to turn on. 2145 * Each word in the array has 1 bit for each switch. 2146 * A bit=1 means the respective memory must be turned on, both array and 2147 * periphery logic; 2148 * bit = 0 means it will stay unchanged (on or off). 2149 * The pointer may be set to NULL, in which case no memory will be changed. 2150 * WARNING: memon must not point to the first shared memory address. 2151 * @callb: pointer to the callback called when configurations are applyed. 2152 * NULL if no callback is required. 2153 * 2154 * The function requests uPower to turn on the PMC and memory array/peripheral 2155 * switches that control their power, as specified above. 2156 * The request is executed if arguments are within range, with no protections 2157 * regarding the adequate memory power state related to overall system state. 2158 * 2159 * If a memory is requested to turn on, but the power switch that feeds that 2160 * memory is not, the power switch will be turned on anyway, if the pwron 2161 * array is not provided (that is, if pwron is NULL). 2162 * 2163 * A callback can be optionally registered, and will be called upon the arrival 2164 * of the request response from the uPower firmware, telling if it succeeded 2165 * or not. 2166 * 2167 * A callback may not be registered (NULL pointer), in which case polling has 2168 * to be used to check the response, by calling upwr_req_status or 2169 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2170 * 2171 * Callback or polling may return error if the service contends for a resource 2172 * already being used by a power mode transition or an ongoing service in 2173 * another domain. 2174 * 2175 * Context: no sleep, no locks taken/released. 2176 * Return: 0 if ok, -1 if service group is busy, 2177 * -2 if a pointer conversion to physical address failed, 2178 * -3 if called in an invalid API state. 2179 * Note that this is not the error response from the request itself: 2180 * it only tells if the request was successfully sent to the uPower. 2181 */ 2182 2183 int upwr_pwm_power_on(const uint32_t swton[], 2184 const uint32_t memon[], 2185 upwr_callb callb) 2186 { 2187 upwr_pwm_pwron_msg txmsg = {0}; 2188 unsigned long ptrval = 0UL; /* needed for X86, ARM64 */ 2189 size_t stsize = 0U; 2190 2191 if (api_state != UPWR_API_READY) { 2192 return -3; 2193 } 2194 2195 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2196 return -1; 2197 } 2198 2199 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2200 2201 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_PWR_ON); 2202 2203 ptrval = (unsigned long)os_ptr2phy((void *)swton); 2204 if (swton == NULL) { 2205 txmsg.ptrs.ptr0 = 0; /* NULL pointer -> 0 offset */ 2206 } else if (ptrval == 0U) { 2207 return -2; /* pointer conversion failed */ 2208 } else { 2209 txmsg.ptrs.ptr0 = upwr_ptr2offset(ptrval, 2210 UPWR_SG_PWRMGMT, 2211 (stsize = UPWR_PMC_SWT_WORDS * 4U), 2212 0U, 2213 swton); 2214 } 2215 2216 ptrval = (unsigned long)os_ptr2phy((void *)memon); 2217 if (memon == NULL) { 2218 txmsg.ptrs.ptr1 = 0; /* NULL pointer -> 0 offset */ 2219 2220 } else if (ptrval == 0U) { 2221 return -2; /* pointer conversion failed */ 2222 } else { 2223 txmsg.ptrs.ptr1 = upwr_ptr2offset(ptrval, 2224 UPWR_SG_PWRMGMT, 2225 UPWR_PMC_MEM_WORDS * 4U, 2226 stsize, 2227 memon); 2228 } 2229 2230 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2231 2232 return 0; 2233 } 2234 2235 /** 2236 * upwr_pwm_power_off()- Powers off (not on) one or more switches and ROM/RAMs. 2237 * @swtoff: pointer to an array of words that tells which power switches to 2238 * turn off. Each word in the array has 1 bit for each switch. 2239 * A bit=1 means the respective switch must be turned off, 2240 * bit = 0 means it will stay unchanged (on or off). 2241 * The pointer may be set to NULL, in which case no switch will be changed. 2242 * WARNING: swtoff must not point to the first shared memory address. 2243 * @memoff: pointer to an array of words that tells which memories to turn off. 2244 * Each word in the array has 1 bit for each switch. 2245 * A bit=1 means the respective memory must be turned off, both array and 2246 * periphery logic; 2247 * bit = 0 means it will stay unchanged (on or off). 2248 * The pointer may be set to NULL, in which case no memory will be changed, 2249 * but notice it may be turned off if the switch that feeds it is powered off. 2250 * WARNING: memoff must not point to the first shared memory address. 2251 * @callb: pointer to the callback called when configurations are applyed. 2252 * NULL if no callback is required. 2253 * 2254 * The function requests uPower to turn off the PMC and memory array/peripheral 2255 * switches that control their power, as specified above. 2256 * The request is executed if arguments are within range, with no protections 2257 * regarding the adequate memory power state related to overall system state. 2258 * 2259 * A callback can be optionally registered, and will be called upon the arrival 2260 * of the request response from the uPower firmware, telling if it succeeded 2261 * or not. 2262 * 2263 * A callback may not be registered (NULL pointer), in which case polling has 2264 * to be used to check the response, by calling upwr_req_status or 2265 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2266 * 2267 * Callback or polling may return error if the service contends for a resource 2268 * already being used by a power mode transition or an ongoing service in 2269 * another domain. 2270 * 2271 * Context: no sleep, no locks taken/released. 2272 * Return: 0 if ok, -1 if service group is busy, 2273 * -2 if a pointer conversion to physical address failed, 2274 * -3 if called in an invalid API state. 2275 * Note that this is not the error response from the request itself: 2276 * it only tells if the request was successfully sent to the uPower. 2277 */ 2278 int upwr_pwm_power_off(const uint32_t swtoff[], 2279 const uint32_t memoff[], 2280 upwr_callb callb) 2281 { 2282 upwr_pwm_pwroff_msg txmsg = {0}; 2283 unsigned long ptrval = 0UL; /* needed for X86, ARM64 */ 2284 size_t stsize = 0; 2285 2286 if (api_state != UPWR_API_READY) { 2287 return -3; 2288 } 2289 2290 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2291 return -1; 2292 } 2293 2294 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2295 2296 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_PWR_OFF); 2297 2298 ptrval = (unsigned long)os_ptr2phy((void *)swtoff); 2299 if (swtoff == NULL) { 2300 txmsg.ptrs.ptr0 = 0; /* NULL pointer -> 0 offset */ 2301 } else if (ptrval == 0U) { 2302 return -2; /* pointer conversion failed */ 2303 } else { 2304 txmsg.ptrs.ptr0 = upwr_ptr2offset(ptrval, 2305 UPWR_SG_PWRMGMT, 2306 (stsize = UPWR_PMC_SWT_WORDS * 4U), 2307 0U, 2308 swtoff); 2309 } 2310 2311 ptrval = (unsigned long)os_ptr2phy((void *)memoff); 2312 if (memoff == NULL) { 2313 txmsg.ptrs.ptr1 = 0; /* NULL pointer -> 0 offset */ 2314 } else if (ptrval == 0U) { 2315 return -2; /* pointer conversion failed */ 2316 } else { 2317 txmsg.ptrs.ptr1 = upwr_ptr2offset(ptrval, 2318 UPWR_SG_PWRMGMT, 2319 UPWR_PMC_MEM_WORDS * 4U, 2320 stsize, 2321 memoff); 2322 } 2323 2324 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2325 2326 return 0; 2327 } 2328 2329 /** 2330 * upwr_pwm_mem_retain()- Configures one or more memory power switches to 2331 * retain its contents, having the power array on, while its peripheral logic 2332 * is turned off. 2333 * @mem: pointer to an array of words that tells which memories to put in a 2334 * retention state. Each word in the array has 1 bit for each memory. 2335 * A bit=1 means the respective memory must be put in retention state, 2336 * bit = 0 means it will stay unchanged (retention, fully on or off). 2337 * @callb: pointer to the callback called when configurations are applyed. 2338 * NULL if no callback is required. 2339 * 2340 * The function requests uPower to turn off the memory peripheral and leave 2341 * its array on, as specified above. 2342 * The request is executed if arguments are within range. 2343 * 2344 * A callback can be optionally registered, and will be called upon the arrival 2345 * of the request response from the uPower firmware, telling if it succeeded 2346 * or not. 2347 * 2348 * A callback may not be registered (NULL pointer), in which case polling has 2349 * to be used to check the response, by calling upwr_req_status or 2350 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2351 * 2352 * Callback or polling may return error if the service contends for a resource 2353 * already being used by a power mode transition or an ongoing service in 2354 * another domain. 2355 * 2356 * Context: no sleep, no locks taken/released. 2357 * Return: 0 if ok, -1 if service group is busy, 2358 * -2 if a pointer conversion to physical address failed, 2359 * -3 if called in an invalid API state. 2360 * Note that this is not the error response from the request itself: 2361 * it only tells if the request was successfully sent to the uPower. 2362 */ 2363 int upwr_pwm_mem_retain(const uint32_t mem[], upwr_callb callb) 2364 { 2365 upwr_pwm_retain_msg txmsg = {0}; 2366 unsigned long ptrval = 0UL; /* needed for X86, ARM64 */ 2367 2368 if (api_state != UPWR_API_READY) { 2369 return -3; 2370 } 2371 2372 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2373 return -1; 2374 } 2375 2376 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2377 2378 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_RETAIN); 2379 2380 ptrval = (unsigned long)os_ptr2phy((void *)mem); 2381 if (ptrval == 0U) { 2382 return -2; /* pointer conversion failed */ 2383 } 2384 2385 txmsg.ptr = upwr_ptr2offset(ptrval, 2386 UPWR_SG_PWRMGMT, 2387 UPWR_PMC_MEM_WORDS * 4U, 2388 0U, 2389 mem); 2390 2391 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2392 2393 return 0; 2394 } 2395 2396 /** 2397 * upwr_pwm_chng_switch_mem() - Turns on/off power on one or more PMC switches 2398 * and memories, including their array and peripheral logic. 2399 * @swt: pointer to a list of PMC switches to be opened/closed. 2400 * The list is structured as an array of struct upwr_switch_board_t 2401 * (see upower_defs.h), each one containing a word for up to 32 switches, 2402 * one per bit. A bit = 1 means switch closed, bit = 0 means switch open. 2403 * struct upwr_switch_board_t also specifies a mask with 1 bit for each 2404 * respective switch: mask bit = 1 means the open/close action is applied, 2405 * mask bit = 0 means the switch stays unchanged. 2406 * The pointer may be set to NULL, in which case no switch will be changed, 2407 * unless a memory that it feeds must be turned on. 2408 * WARNING: swt must not point to the first shared memory address. 2409 * @mem: pointer to a list of switches to be turned on/off. 2410 * The list is structured as an array of struct upwr_mem_switches_t 2411 * (see upower_defs.h), each one containing 2 word for up to 32 switches, 2412 * one per bit, one word for the RAM array power switch, other for the 2413 * RAM peripheral logic power switch. A bit = 1 means switch closed, 2414 * bit = 0 means switch open. 2415 * struct upwr_mem_switches_t also specifies a mask with 1 bit for each 2416 * respective switch: mask bit = 1 means the open/close action is applied, 2417 * mask bit = 0 means the switch stays unchanged. 2418 * The pointer may be set to NULL, in which case no memory switch will be 2419 * changed, but notice it may be turned off if the switch that feeds it is 2420 * powered off. 2421 * WARNING: mem must not point to the first shared memory address. 2422 * @callb: pointer to the callback called when the configurations are applied. 2423 * NULL if no callback is required. 2424 * 2425 * The function requests uPower to change the PMC switches and/or memory power 2426 * as specified above. 2427 * The request is executed if arguments are within range, with no protections 2428 * regarding the adequate switch combinations and overall system state. 2429 * 2430 * If a memory is requested to turn on, but the power switch that feeds that 2431 * memory is not, the power switch will be turned on anyway, if the swt 2432 * array is not provided (that is, if swt is NULL). 2433 * 2434 * A callback can be optionally registered, and will be called upon the arrival 2435 * of the request response from the uPower firmware, telling if it succeeded 2436 * or not. 2437 * 2438 * A callback may not be registered (NULL pointer), in which case polling has 2439 * to be used to check the response, by calling upwr_req_status or 2440 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2441 * 2442 * Callback or polling may return error if the service contends for a resource 2443 * already being used by a power mode transition or an ongoing service in 2444 * another domain. 2445 * 2446 * Context: no sleep, no locks taken/released. 2447 * Return: 0 if ok, -1 if service group is busy. 2448 * -2 if a pointer conversion to physical address failed, 2449 * -3 if called in an invalid API state. 2450 * Note that this is not the error response from the request itself: 2451 * it only tells if the request was successfully sent to the uPower. 2452 */ 2453 2454 int upwr_pwm_chng_switch_mem(const struct upwr_switch_board_t swt[], 2455 const struct upwr_mem_switches_t mem[], 2456 upwr_callb callb) 2457 { 2458 upwr_pwm_switch_msg txmsg = {0}; 2459 unsigned long ptrval = 0UL; /* needed for X86, ARM64 */ 2460 size_t stsize = 0U; 2461 2462 if (api_state != UPWR_API_READY) { 2463 return -3; 2464 } 2465 2466 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2467 return -1; 2468 } 2469 2470 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2471 2472 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_SWITCH); 2473 2474 ptrval = (unsigned long)os_ptr2phy((void *)swt); 2475 if (swt == NULL) { 2476 txmsg.ptrs.ptr0 = 0; /* NULL pointer -> 0 offset */ 2477 } else if (ptrval == 0U) { 2478 return -2; /* pointer conversion failed */ 2479 } else { 2480 txmsg.ptrs.ptr0 = upwr_ptr2offset(ptrval, 2481 UPWR_SG_PWRMGMT, 2482 (stsize = UPWR_PMC_SWT_WORDS * sizeof(struct upwr_switch_board_t)), 2483 0U, 2484 swt); 2485 } 2486 2487 ptrval = (unsigned long)os_ptr2phy((void *)mem); 2488 if (mem == NULL) { 2489 txmsg.ptrs.ptr1 = 0; /* NULL pointer -> 0 offset */ 2490 } else if (ptrval == 0U) { 2491 return -2; /* pointer conversion failed */ 2492 } else { 2493 txmsg.ptrs.ptr1 = upwr_ptr2offset(ptrval, 2494 UPWR_SG_PWRMGMT, 2495 UPWR_PMC_MEM_WORDS * sizeof(struct upwr_mem_switches_t), 2496 stsize, 2497 mem); 2498 } 2499 2500 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2501 2502 return 0; 2503 } 2504 2505 /** 2506 * upwr_pwm_pmode_config() - Configures a given power mode in a given domain. 2507 * @domain: identifier of the domain to which the power mode belongs. 2508 * Defined by SoC-dependent type soc_domain_t found in upower_soc_defs.h. 2509 * @pmode: SoC-dependent power mode identifier defined by type abs_pwr_mode_t 2510 * found in upower_soc_defs.h. 2511 * @config: pointer to an SoC-dependent struct defining the power mode 2512 * configuration, found in upower_soc_defs.h. 2513 * @callb: pointer to the callback called when configurations are applied. 2514 * NULL if no callback is required. 2515 * 2516 * The function requests uPower to change the power mode configuration as 2517 * specified above. The request is executed if arguments are within range, 2518 * and complies with SoC-dependent restrictions on value combinations. 2519 * 2520 * A callback can be optionally registered, and will be called upon the arrival 2521 * of the request response from the uPower firmware, telling if it succeeded 2522 * or not. 2523 * 2524 * A callback may not be registered (NULL pointer), in which case polling has 2525 * to be used to check the response, by calling upwr_req_status or 2526 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2527 * 2528 * Context: no sleep, no locks taken/released. 2529 * Return: 0 if ok, -1 if service group is busy, 2530 * -2 if the pointer conversion to physical address failed, 2531 * -3 if called in an invalid API state. 2532 * Note that this is not the error response from the request itself: 2533 * it only tells if the request was successfully sent to the uPower. 2534 */ 2535 int upwr_pwm_pmode_config(soc_domain_t domain, 2536 abs_pwr_mode_t pmode, 2537 const void *config, 2538 upwr_callb callb) 2539 { 2540 upwr_pwm_pmode_cfg_msg txmsg = {0}; 2541 unsigned long ptrval = 0UL; /* needed for X86, ARM64 */ 2542 2543 if (api_state != UPWR_API_READY) { 2544 return -3; 2545 } 2546 2547 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2548 return -1; 2549 } 2550 2551 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2552 2553 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_CONFIG); 2554 txmsg.hdr.domain = (uint32_t)domain; 2555 txmsg.hdr.arg = pmode; 2556 2557 ptrval = (unsigned long)os_ptr2phy(config); 2558 if (ptrval == 0U) { 2559 return -2; /* pointer conversion failed */ 2560 } 2561 2562 /* 2563 * upwr_pwm_pmode_config is an exception: use the pointer 2564 * (physical addr) as is 2565 */ 2566 2567 txmsg.ptr = (uint32_t)ptrval; 2568 2569 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2570 2571 return 0; 2572 } 2573 2574 /** 2575 * upwr_pwm_reg_config() - Configures the uPower internal regulators. 2576 * @config: pointer to the struct defining the regulator configuration; 2577 * the struct upwr_reg_config_t is defined in the file upower_defs.h. 2578 * @callb: pointer to the callback called when configurations are applied. 2579 * NULL if no callback is required. 2580 * 2581 * The function requests uPower to change/define the configurations of the 2582 * internal regulators. 2583 * 2584 * A callback can be optionally registered, and will be called upon the arrival 2585 * of the request response from the uPower firmware, telling if it succeeded 2586 * or not. 2587 * 2588 * A callback may not be registered (NULL pointer), in which case polling has 2589 * to be used to check the response, by calling upwr_req_status or 2590 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2591 * 2592 * The service may fail with error UPWR_RESP_RESOURCE if a power mode transition 2593 * or the same service (called from another domain) is executing simultaneously. 2594 * This error should be interpreted as a "try later" response, as the service 2595 * will succeed once those concurrent executions are done, and no other is 2596 * started. 2597 * 2598 * Context: no sleep, no locks taken/released. 2599 * Return: 0 if ok, -1 if service group is busy, 2600 * -2 if the pointer conversion to physical address failed, 2601 * -3 if called in an invalid API state. 2602 * Note that this is not the error response from the request itself: 2603 * it only tells if the request was successfully sent to the uPower. 2604 */ 2605 2606 int upwr_pwm_reg_config(const struct upwr_reg_config_t *config, 2607 upwr_callb callb) 2608 { 2609 upwr_pwm_regcfg_msg txmsg = {0}; 2610 unsigned long ptrval = 0UL; /* needed for X86, ARM64 */ 2611 2612 if (api_state != UPWR_API_READY) { 2613 return -3; 2614 } 2615 2616 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2617 return -1; 2618 } 2619 2620 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2621 2622 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_REGCFG); 2623 2624 ptrval = (unsigned long)os_ptr2phy(config); 2625 if (ptrval == 0U) { 2626 return -2; /* pointer conversion failed */ 2627 } 2628 2629 txmsg.ptr = upwr_ptr2offset(ptrval, 2630 UPWR_SG_PWRMGMT, 2631 sizeof(struct upwr_reg_config_t), 2632 0U, 2633 config); 2634 2635 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2636 2637 return 0; 2638 } 2639 2640 /** 2641 * upwr_pwm_chng_dom_bias() - Changes the domain bias. 2642 * @bias: pointer to a domain bias configuration struct (see upower_soc_defs.h). 2643 * @callb: pointer to the callback called when configurations are applied. 2644 * NULL if no callback is required. 2645 * 2646 * The function requests uPower to change the domain bias configuration as 2647 * specified above. The request is executed if arguments are within range, 2648 * with no protections regarding the adequate value combinations and 2649 * overall system state. 2650 * 2651 * A callback can be optionally registered, and will be called upon the arrival 2652 * of the request response from the uPower firmware, telling if it succeeded 2653 * or not. 2654 * 2655 * A callback may not be registered (NULL pointer), in which case polling has 2656 * to be used to check the response, by calling upwr_req_status or 2657 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2658 * 2659 * Context: no sleep, no locks taken/released. 2660 * Return: 0 if ok, -1 if service group is busy, 2661 * -3 if called in an invalid API state. 2662 * Note that this is not the error response from the request itself: 2663 * it only tells if the request was successfully sent to the uPower. 2664 */ 2665 int upwr_pwm_chng_dom_bias(const struct upwr_dom_bias_cfg_t *bias, 2666 upwr_callb callb) 2667 { 2668 upwr_pwm_dom_bias_msg txmsg = {0}; 2669 2670 if (api_state != UPWR_API_READY) { 2671 return -3; 2672 } 2673 2674 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2675 return -1; 2676 } 2677 2678 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2679 2680 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_DOM_BIAS); 2681 2682 /* SoC-dependent argument filling, defined in upower_soc_defs.h */ 2683 UPWR_FILL_DOMBIAS_ARGS(txmsg.hdr.domain, bias, txmsg.args); 2684 2685 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2686 2687 return 0; 2688 } 2689 2690 /** 2691 * upwr_pwm_chng_mem_bias()- Changes a ROM/RAM power bias. 2692 * @domain: identifier of the domain upon which the bias is applied. 2693 * Defined by SoC-dependent type soc_domain_t found in upower_soc_defs.h. 2694 * @bias: pointer to a memory bias configuration struct (see upower_soc_defs.h). 2695 * @callb: pointer to the callback called when configurations are applied. 2696 * NULL if no callback is required. 2697 * 2698 * The function requests uPower to change the memory bias configuration as 2699 * specified above. The request is executed if arguments are within range, 2700 * with no protections regarding the adequate value combinations and 2701 * overall system state. 2702 * 2703 * A callback can be optionally registered, and will be called upon the arrival 2704 * of the request response from the uPower firmware, telling if it succeeded 2705 * or not. 2706 * 2707 * A callback may not be registered (NULL pointer), in which case polling has 2708 * to be used to check the response, by calling upwr_req_status or 2709 * upwr_poll_req_status, using UPWR_SG_PWRMGMT as the service group argument. 2710 * 2711 * Context: no sleep, no locks taken/released. 2712 * Return: 0 if ok, -1 if service group is busy, 2713 * -3 if called in an invalid API state. 2714 * Note that this is not the error response from the request itself: 2715 * it only tells if the request was successfully sent to the uPower. 2716 */ 2717 int upwr_pwm_chng_mem_bias(soc_domain_t domain, 2718 const struct upwr_mem_bias_cfg_t *bias, 2719 upwr_callb callb) 2720 { 2721 upwr_pwm_mem_bias_msg txmsg = {0}; 2722 2723 if (api_state != UPWR_API_READY) { 2724 return -3; 2725 } 2726 2727 if (UPWR_SG_BUSY(UPWR_SG_PWRMGMT)) { 2728 return -1; 2729 } 2730 2731 UPWR_USR_CALLB(UPWR_SG_PWRMGMT, callb); 2732 2733 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_PWRMGMT, UPWR_PWM_MEM_BIAS); 2734 2735 txmsg.hdr.domain = (uint32_t)domain; 2736 2737 /* SoC-dependent argument filling, defined in upower_soc_defs.h */ 2738 UPWR_FILL_MEMBIAS_ARGS(bias, txmsg.args); 2739 2740 upwr_srv_req(UPWR_SG_PWRMGMT, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2741 2742 return 0; 2743 } 2744 2745 /**--------------------------------------------------------------- 2746 * DIAGNOSE SERVICE GROUP 2747 */ 2748 2749 /** 2750 * upwr_dgn_mode() - Sets the diagnostic mode. 2751 * @mode: diagnostic mode, which can be: 2752 * - UPWR_DGN_NONE: no diagnostic recorded 2753 * - UPWR_DGN_TRACE: warnings, errors, service, internal activity recorded 2754 * - UPWR_DGN_SRVREQ: warnings, errors, service activity recorded 2755 * - UPWR_DGN_WARN: warnings and errors recorded 2756 * - UPWR_DGN_ALL: trace, service, warnings, errors, task state recorded 2757 * - UPWR_DGN_ERROR: only errors recorded 2758 * - UPWR_DGN_ALL2ERR: record all until an error occurs, 2759 * freeze recording on error 2760 * - UPWR_DGN_ALL2HLT: record all until an error occurs, 2761 * executes an ebreak on error, which halts the core if enabled through 2762 * the debug interface 2763 * @callb: pointer to the callback called when mode is changed. 2764 * NULL if no callback is required. 2765 * 2766 * Context: no sleep, no locks taken/released. 2767 * Return: 0 if ok, 2768 * -1 if service group is busy, 2769 * -3 if called in an invalid API state 2770 */ 2771 int upwr_dgn_mode(upwr_dgn_mode_t mode, const upwr_callb callb) 2772 { 2773 upwr_dgn_mode_msg txmsg = {0}; 2774 2775 if (UPWR_SG_BUSY(UPWR_SG_DIAG)) { 2776 return -1; 2777 } 2778 2779 UPWR_USR_CALLB(UPWR_SG_DIAG, callb); 2780 2781 UPWR_MSG_HDR(txmsg.hdr, UPWR_SG_DIAG, UPWR_DGN_MODE); 2782 2783 txmsg.hdr.arg = mode; 2784 2785 upwr_srv_req(UPWR_SG_DIAG, (uint32_t *)&txmsg, sizeof(txmsg) / 4U); 2786 2787 return 0; 2788 } 2789 2790 /**--------------------------------------------------------------- 2791 * AUXILIARY CALLS 2792 */ 2793 2794 /** 2795 * upwr_rom_version() - informs the ROM firwmware version. 2796 * @vmajor: pointer to the variable to get the firmware major version number. 2797 * @vminor: pointer to the variable to get the firmware minor version number. 2798 * @vfixes: pointer to the variable to get the firmware fixes number. 2799 * 2800 * Context: no sleep, no locks taken/released. 2801 * Return: SoC id. 2802 */ 2803 uint32_t upwr_rom_version(uint32_t *vmajor, uint32_t *vminor, uint32_t *vfixes) 2804 { 2805 uint32_t soc; 2806 2807 upwr_lock(1); 2808 soc = fw_rom_version.soc_id; 2809 *vmajor = fw_rom_version.vmajor; 2810 *vminor = fw_rom_version.vminor; 2811 *vfixes = fw_rom_version.vfixes; 2812 upwr_lock(0); 2813 return soc; 2814 } 2815 2816 /** 2817 * upwr_ram_version() - informs the RAM firwmware version. 2818 * @vminor: pointer to the variable to get the firmware minor version number. 2819 * @vfixes: pointer to the variable to get the firmware fixes number. 2820 * 2821 * The 3 values returned are 0 if no RAM firmwmare was loaded and initialized. 2822 * 2823 * Context: no sleep, no locks taken/released. 2824 * Return: firmware major version number. 2825 */ 2826 uint32_t upwr_ram_version(uint32_t *vminor, uint32_t *vfixes) 2827 { 2828 uint32_t vmajor; 2829 2830 upwr_lock(1); 2831 vmajor = fw_ram_version.vmajor; 2832 *vminor = fw_ram_version.vminor; 2833 *vfixes = fw_ram_version.vfixes; 2834 upwr_lock(0); 2835 2836 return vmajor; 2837 } 2838 2839 /** 2840 * upwr_req_status() - tells the status of the service group request, and 2841 * returns a request return value, if any. 2842 * @sg: service group of the request 2843 * @sgfptr: pointer to the variable that will hold the function id of 2844 * the last request completed; can be NULL, in which case it is not used. 2845 * @errptr: pointer to the variable that will hold the error code; 2846 * can be NULL, in which case it is not used. 2847 * @retptr: pointer to the variable that will hold the value returned 2848 * by the last request completed (invalid if the last request completed didn't 2849 * return any value); can be NULL, in which case it is not used. 2850 * Note that a request may return a value even if service error is returned 2851 * (*errptr != UPWR_RESP_OK): that is dependent on the specific service. 2852 * 2853 * This call can be used in a poll loop of a service request completion in case 2854 * a callback was not registered. 2855 * 2856 * Context: no sleep, no locks taken/released. 2857 * Return: service request status: succeeded, failed, or ongoing (busy) 2858 */ 2859 upwr_req_status_t upwr_req_status(upwr_sg_t sg, 2860 uint32_t *sgfptr, 2861 upwr_resp_t *errptr, 2862 int *retptr) 2863 { 2864 upwr_req_status_t status; 2865 2866 upwr_lock(1); 2867 if (sgfptr != NULL) { 2868 *sgfptr = (uint32_t)sg_rsp_msg[sg].hdr.function; 2869 } 2870 2871 if (errptr != NULL) { 2872 *errptr = (upwr_resp_t)sg_rsp_msg[sg].hdr.errcode; 2873 } 2874 2875 if (retptr != NULL) { 2876 *retptr = (int)((sg_rsp_siz[sg] == 2U) ? 2877 sg_rsp_msg[sg].word2 : sg_rsp_msg[sg].hdr.ret); 2878 } 2879 2880 status = ((sg_busy & (1UL << sg)) == 1U) ? UPWR_REQ_BUSY : 2881 (sg_rsp_msg[sg].hdr.errcode == UPWR_RESP_OK) ? UPWR_REQ_OK : 2882 UPWR_REQ_ERR; 2883 upwr_lock(0); 2884 return status; 2885 } 2886 2887 /** 2888 * upwr_poll_req_status() - polls the status of the service group request, and 2889 * returns a request return value, if any. 2890 * @sg: service group of the request 2891 * @sgfptr: pointer to the variable that will hold the function id of 2892 * the last request completed; can be NULL, in which case it is not used. 2893 * @errptr: pointer to the variable that will hold the error code; 2894 * can be NULL, in which case it is not used. 2895 * @retptr: pointer to the variable that will hold the value returned 2896 * by the last request completed (invalid if the last request completed didn't 2897 * return any value); can be NULL, in which case it is not used. 2898 * Note that a request may return a value even if service error is returned 2899 * (*errptr != UPWR_RESP_OK): that is dependent on the specific service. 2900 * @attempts: maximum number of polling attempts; if attempts > 0 and is 2901 * reached with no service response received, upwr_poll_req_status returns 2902 * UPWR_REQ_BUSY and variables pointed by sgfptr, retptr and errptr are not 2903 * updated; if attempts = 0, upwr_poll_req_status waits "forever". 2904 * 2905 * This call can be used to poll a service request completion in case a 2906 * callback was not registered. 2907 * 2908 * Context: no sleep, no locks taken/released. 2909 * Return: service request status: succeeded, failed, or ongoing (busy) 2910 */ 2911 upwr_req_status_t upwr_poll_req_status(upwr_sg_t sg, 2912 uint32_t *sgfptr, 2913 upwr_resp_t *errptr, 2914 int *retptr, 2915 uint32_t attempts) 2916 { 2917 uint32_t i; 2918 upwr_req_status_t ret; 2919 2920 if (attempts == 0U) { 2921 while ((ret = upwr_req_status(sg, sgfptr, errptr, retptr)) == UPWR_REQ_BUSY) { 2922 }; 2923 2924 return ret; 2925 } 2926 2927 for (i = 0U; i < attempts; i++) { 2928 ret = upwr_req_status(sg, sgfptr, errptr, retptr); 2929 if (ret != UPWR_REQ_BUSY) { 2930 break; 2931 } 2932 } 2933 2934 return ret; 2935 } 2936 2937 /** 2938 * upwr_alarm_code() - returns the alarm code of the last alarm occurrence. 2939 * 2940 * The value returned is not meaningful if no alarm was issued by uPower. 2941 * 2942 * Context: no sleep, no locks taken/released. 2943 * Return: alarm code, as defined by the type upwr_alarm_t in upwr_soc_defines.h 2944 */ 2945 upwr_alarm_t upwr_alarm_code(void) 2946 { 2947 return (upwr_alarm_t)(3U & (mu->FSR.R >> 1U)); /* FSR[2:1] */ 2948 } 2949 2950 /**--------------------------------------------------------------- 2951 * TRANSMIT/RECEIVE PRIMITIVES 2952 * --------------------------------------------------------------- 2953 */ 2954 2955 /* 2956 * upwr_copy2tr() - copies a message to the MU TR registers; 2957 * fill the TR registers before writing TIEN to avoid early interrupts; 2958 * also, fill them from the higher index to the lowest, so the receive 2959 * interrupt flag RF[0] will be the last to set, regardless of message size; 2960 */ 2961 void upwr_copy2tr(struct MU_t *local_mu, const uint32_t *msg, unsigned int size) 2962 { 2963 for (int i = (int)size - 1; i > -1; i--) { 2964 local_mu->TR[i].R = msg[i]; 2965 } 2966 } 2967 2968 /** 2969 * upwr_tx() - queues a message for transmission. 2970 * @msg : pointer to the message sent. 2971 * @size: message size in 32-bit words 2972 * @callback: pointer to a function to be called when transmission done; 2973 * can be NULL, in which case no callback is done. 2974 * 2975 * This is an auxiliary function used by the rest of the API calls. 2976 * It is normally not called by the driver code, unless maybe for test purposes. 2977 * 2978 * Context: no sleep, no locks taken/released. 2979 * Return: number of vacant positions left in the transmission queue, or 2980 * -1 if the queue was already full when upwr_tx was called, or 2981 * -2 if any argument is invalid (like size off-range) 2982 */ 2983 int upwr_tx(const uint32_t *msg, 2984 unsigned int size, 2985 UPWR_TX_CALLB_FUNC_T callback) 2986 { 2987 if (size > UPWR_MU_MSG_SIZE) { 2988 return -2; 2989 } 2990 2991 if (size == 0U) { 2992 return -2; 2993 } 2994 2995 if (mu->TSR.R != UPWR_MU_TSR_EMPTY) { 2996 return -1; /* not all TE bits in 1: some data to send still */ 2997 } 2998 2999 mu_tx_callb = callback; 3000 3001 upwr_copy2tr(mu, msg, size); 3002 mu->TCR.R = 1UL << (size - 1UL); 3003 3004 mu_tx_pend = 1UL; 3005 3006 return 0; 3007 } 3008 3009 /** 3010 * upwr_rx() - unqueues a received message from the reception queue. 3011 * @msg: pointer to the message destination buffer. 3012 * @size: pointer to variable to hold message size in 32-bit words. 3013 * 3014 * This is an auxiliary function used by the rest of the API calls. 3015 * It is normally not called by the driver code, unless maybe for test purposes. 3016 * 3017 * Context: no sleep, no locks taken/released. 3018 * Return: number of messages remaining in the reception queue, or 3019 * -1 if the queue was already empty when upwr_rx was called, or 3020 * -2 if any argument is invalid (like mu off-range) 3021 */ 3022 int upwr_rx(char *msg, unsigned int *size) 3023 { 3024 unsigned int len = mu->RSR.R; 3025 3026 len = (len == 0x0U) ? 0U : 3027 (len == 0x1U) ? 1U : 3028 #if UPWR_MU_MSG_SIZE > 1 3029 (len == 0x3U) ? 2U : 3030 #if UPWR_MU_MSG_SIZE > 2 3031 (len == 0x7U) ? 3U : 3032 #if UPWR_MU_MSG_SIZE > 3 3033 (len == 0xFU) ? 4U : 3034 #endif 3035 #endif 3036 #endif 3037 0xFFFFFFFFU; /* something wrong */ 3038 3039 if (len == 0xFFFFFFFFU) { 3040 return -3; 3041 } 3042 3043 if (len == 0U) { 3044 return -1; 3045 } 3046 3047 *size = len; 3048 3049 /* 3050 * copy the received message to the rx queue, 3051 * so the interrupts are cleared. 3052 */ 3053 msg_copy(msg, (char *)&mu->RR[0], len); 3054 3055 mu->RCR.R = 1U; /* enable only RR[0] receive interrupt */ 3056 3057 return 0; 3058 } 3059 3060 /** 3061 * upwr_rx_callback() - sets up a callback for a message receiving event. 3062 * @callback: pointer to a function to be called when a message arrives; 3063 * can be NULL, in which case no callback is done. 3064 * 3065 * This is an auxiliary function used by the rest of the API calls. 3066 * It is normally not called by the driver code, unless maybe for test purposes. 3067 * 3068 * Context: no sleep, no locks taken/released. 3069 * Return: 0 if ok; -2 if any argument is invalid (mu off-range). 3070 */ 3071 int upwr_rx_callback(UPWR_RX_CALLB_FUNC_T callback) 3072 { 3073 mu_rx_callb = callback; 3074 3075 return 0; 3076 } 3077 3078 /** 3079 * msg_copy() - copies a message. 3080 * @dest: pointer to the destination message. 3081 * @src : pointer to the source message. 3082 * @size: message size in words. 3083 * 3084 * This is an auxiliary function used by the rest of the API calls. 3085 * It is normally not called by the driver code, unless maybe for test purposes. 3086 * 3087 * Context: no sleep, no locks taken/released. 3088 * Return: none (void) 3089 */ 3090 void msg_copy(char *dest, char *src, unsigned int size) 3091 { 3092 for (uint32_t i = 0U; i < size * sizeof(uint32_t); i++) { 3093 dest[i] = src[i]; 3094 } 3095 } 3096