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 */
ptr2phys(const void * ptr)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
upwr_ptr2offset(unsigned long ptr,upwr_sg_t sg,size_t siz,size_t offset,const void * vptr)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 */
upwr_lock(int lock)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 */
upwr_exp_isr(void)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 */
upwr_txrx_isr(void)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 */
upwr_next_req(void)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 */
upwr_mu_int_callback(void)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 */
upwr_srv_req(upwr_sg_t sg,uint32_t * msg,unsigned int size)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 */
upwr_start_callb(void)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 */
upwr_init(soc_domain_t domain,struct MU_t * muptr,const upwr_malloc_ptr_t mallocptr,const upwr_phyadr_ptr_t phyadrptr,const upwr_inst_isr_ptr_t isrinstptr,const upwr_lock_ptr_t lockptr)488*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 */
upwr_start(uint32_t launchopt,const upwr_rdy_callb rdycallb)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 */
upwr_xcp_config(const upwr_xcp_config_t * config,const upwr_callb callb)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 */
upwr_xcp_sw_alarm(soc_domain_t domain,upwr_alarm_t code,const upwr_callb callb)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 */
upwr_xcp_set_ddr_retention(soc_domain_t domain,uint32_t enable,const upwr_callb callb)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 */
upwr_xcp_set_mipi_dsi_ena(soc_domain_t domain,uint32_t enable,const upwr_callb callb)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 */
upwr_xcp_get_mipi_dsi_ena(soc_domain_t domain,const upwr_callb callb)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 */
upwr_xcp_set_osc_mode(soc_domain_t domain,uint32_t osc_mode,const upwr_callb callb)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 */
upwr_xcp_set_rtd_use_ddr(soc_domain_t domain,uint32_t is_use_ddr,const upwr_callb callb)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 */
upwr_xcp_set_rtd_apd_llwu(soc_domain_t domain,uint32_t enable,const upwr_callb callb)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 */
upwr_xcp_shutdown(const upwr_callb callb)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
upwr_xcp_i2c_access(uint16_t addr,int8_t data_size,uint8_t subaddr_size,uint32_t subaddr,uint32_t wdata,const upwr_callb callb)1144*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 */
upwr_vtm_pmic_cold_reset(upwr_callb callb)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 */
upwr_vtm_set_pmic_mode(uint32_t pmic_mode,upwr_callb callb)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 */
upwr_vtm_chng_pmic_voltage(uint32_t rail,uint32_t volt,upwr_callb callb)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 */
upwr_vtm_get_pmic_voltage(uint32_t rail,upwr_callb callb)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 */
upwr_vtm_power_measure(uint32_t ssel,upwr_callb callb)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 */
upwr_vtm_vmeter_measure(uint32_t vdetsel,upwr_callb callb)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 */
upwr_vtm_pmic_config(const void * config,uint32_t size,upwr_callb callb)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 */
upwr_tpm_get_temperature(uint32_t sensor_id,upwr_callb callb)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 */
upwr_dlm_get_delay_margin(uint32_t path,uint32_t index,upwr_callb callb)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 */
upwr_dlm_set_delay_margin(uint32_t path,uint32_t index,uint32_t delay_margin,upwr_callb callb)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 */
upwr_dlm_process_monitor(uint32_t chain_sel,upwr_callb callb)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 */
upwr_pwm_dom_power_on(soc_domain_t domain,int boot_start,const upwr_callb pwroncallb)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 */
upwr_pwm_boot_start(soc_domain_t domain,const upwr_callb bootcallb)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 */
upwr_pwm_param(upwr_pwm_param_t * param,const upwr_callb callb)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 */
upwr_pwm_chng_reg_voltage(uint32_t reg,uint32_t volt,upwr_callb callb)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 */
upwr_pwm_freq_setup(soc_domain_t domain,uint32_t rail,uint32_t stage,uint32_t target_freq,upwr_callb callb)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
upwr_pwm_power_on(const uint32_t swton[],const uint32_t memon[],upwr_callb callb)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 */
upwr_pwm_power_off(const uint32_t swtoff[],const uint32_t memoff[],upwr_callb callb)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 */
upwr_pwm_mem_retain(const uint32_t mem[],upwr_callb callb)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
upwr_pwm_chng_switch_mem(const struct upwr_switch_board_t swt[],const struct upwr_mem_switches_t mem[],upwr_callb callb)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 */
upwr_pwm_pmode_config(soc_domain_t domain,abs_pwr_mode_t pmode,const void * config,upwr_callb callb)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
upwr_pwm_reg_config(const struct upwr_reg_config_t * config,upwr_callb callb)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 */
upwr_pwm_chng_dom_bias(const struct upwr_dom_bias_cfg_t * bias,upwr_callb callb)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 */
upwr_pwm_chng_mem_bias(soc_domain_t domain,const struct upwr_mem_bias_cfg_t * bias,upwr_callb callb)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 */
upwr_dgn_mode(upwr_dgn_mode_t mode,const upwr_callb callb)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 */
upwr_rom_version(uint32_t * vmajor,uint32_t * vminor,uint32_t * vfixes)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 */
upwr_ram_version(uint32_t * vminor,uint32_t * vfixes)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 */
upwr_req_status(upwr_sg_t sg,uint32_t * sgfptr,upwr_resp_t * errptr,int * retptr)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 */
upwr_poll_req_status(upwr_sg_t sg,uint32_t * sgfptr,upwr_resp_t * errptr,int * retptr,uint32_t attempts)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 */
upwr_alarm_code(void)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 */
upwr_copy2tr(struct MU_t * local_mu,const uint32_t * msg,unsigned int size)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 */
upwr_tx(const uint32_t * msg,unsigned int size,UPWR_TX_CALLB_FUNC_T callback)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 */
upwr_rx(char * msg,unsigned int * size)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 */
upwr_rx_callback(UPWR_RX_CALLB_FUNC_T callback)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 */
msg_copy(char * dest,char * src,unsigned int size)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