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