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