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