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