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