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