1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2015-2023, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Description:
8 * Power domain management support.
9 */
10
11 #include <mod_power_domain.h>
12
13 #include <fwk_assert.h>
14 #include <fwk_core.h>
15 #include <fwk_event.h>
16 #include <fwk_id.h>
17 #include <fwk_log.h>
18 #include <fwk_macros.h>
19 #include <fwk_mm.h>
20 #include <fwk_module.h>
21 #include <fwk_module_idx.h>
22 #include <fwk_notification.h>
23 #include <fwk_status.h>
24
25 #include <inttypes.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdio.h>
29
30 /*
31 * Module and power domain contexts
32 */
33
34 struct response_ctx {
35 /* Pending response flag. */
36 bool pending;
37
38 /* Cookie of the event to respond to. */
39 uint32_t cookie;
40 };
41
42 /* Context for the power state transition notification */
43 struct mod_power_state_transition_notification_ctx {
44 /* Number of pending notification responses */
45 unsigned int pending_responses;
46
47 /*
48 * Power state the power domain has transitioned to.
49 */
50 unsigned int state;
51
52 /* Storage for pre-transition power state */
53 unsigned int previous_state;
54 };
55
56 /* Context for the power state pre-transition notification */
57 struct mod_power_state_pre_transition_notification_ctx {
58 /* Number of pending notification responses */
59 unsigned int pending_responses;
60
61 /* Target power state */
62 unsigned int state;
63
64 /*
65 * Status of the responses received so far. Either FWK_SUCCESS if all the
66 * responses received so far have indicated success, or FWK_E_DEVICE
67 * otherwise.
68 */
69 int response_status;
70
71 /*
72 * Validity flag. Set to true when a notification is sent and reset to
73 * false when the requested state for the power domain is changed.
74 */
75 bool valid;
76 };
77
78 struct pd_ctx {
79 /* Identifier of the power domain */
80 fwk_id_t id;
81
82 /* Driver interface */
83 struct mod_pd_driver_api *driver_api;
84
85 /* Driver's identifier of the power domain */
86 fwk_id_t driver_id;
87
88 /* Power domain configuration data */
89 const struct mod_power_domain_element_config *config;
90
91 /*
92 * Mask of the valid states. Bit \c n in ::valid_states_mask is equal
93 * to one if and only if the state \c n is a valid state for the power
94 * domain. The number of bits of this field has to be greater or equal than
95 * MOD_PD_STATE_COUNT_MAX.
96 */
97 uint32_t valid_state_mask;
98
99 /*
100 * Table of allowed state masks. Bit \c n of the entry \c m is equal to
101 * one if and only if the state \c n for the power domain is allowed when
102 * its parent is in state \c m. The number of bits of each entry of this
103 * table has to be greater or equal than MOD_PD_STATE_COUNT_MAX.
104 */
105 const uint32_t *allowed_state_mask_table;
106
107 /* Size of the table of allowed state masks */
108 size_t allowed_state_mask_table_size;
109
110 /* Composite state is supported */
111 bool cs_support;
112
113 /*
114 * Composite state mask table. This table provides the mask for each level
115 */
116 const uint32_t *composite_state_mask_table;
117
118 /* Size of the composite state mask table */
119 size_t composite_state_mask_table_size;
120
121 /* Composite state number of levels mask */
122 uint32_t composite_state_levels_mask;
123
124 /* Pointer to the power domain's parent context */
125 struct pd_ctx *parent;
126
127 /*
128 * List if all power domain children if any.
129 */
130 struct fwk_slist children_list;
131
132 /*
133 * Node in the parent list if not the root
134 */
135 struct fwk_slist_node child_node;
136
137 /* Requested power state for the power domain */
138 unsigned int requested_state;
139
140 /* Last power state requested to the driver for the power domain */
141 unsigned int state_requested_to_driver;
142
143 /*
144 * Current state of the power domain. When a transition is in progress, the
145 * current state is different from the last requested state.
146 */
147 unsigned int current_state;
148
149 /* Pending response context */
150 struct response_ctx response;
151
152 /* Context for the power state transition notification */
153 struct mod_power_state_transition_notification_ctx
154 power_state_transition_notification_ctx;
155
156 /* Context for the power state pre-transition notification */
157 struct mod_power_state_pre_transition_notification_ctx
158 power_state_pre_transition_notification_ctx;
159 };
160
161 struct system_suspend_ctx {
162 /*
163 * Flag indicating if the last core is being turned off (true) or not
164 * (false).
165 */
166 bool last_core_off_ongoing;
167
168 /*
169 * Flag indicating if the system is being suspended (true) or not (false).
170 */
171 bool suspend_ongoing;
172
173 /* Last standing core context */
174 struct pd_ctx *last_core_pd;
175
176 /* Suspend state for the system power domain */
177 unsigned int state;
178 };
179
180 struct system_shutdown_ctx {
181 /* Flag indicating if a system shutdown is ongoing */
182 bool ongoing;
183
184 /* Total count of notifications sent for system shutdown */
185 unsigned int notifications_count;
186
187 /* Type of system shutdown */
188 enum mod_pd_system_shutdown system_shutdown;
189
190 /* Cookie of the event to respond to */
191 uint32_t cookie;
192 };
193
194 struct mod_pd_mod_ctx {
195 /* Module configuration data */
196 struct mod_power_domain_config *config;
197
198 /* Table of power domain contexts */
199 struct pd_ctx *pd_ctx_table;
200
201 /* Number of power domains */
202 unsigned int pd_count;
203
204 /* Context of the system power domain */
205 struct pd_ctx *system_pd_ctx;
206
207 /* System suspend context */
208 struct system_suspend_ctx system_suspend;
209
210 /* System shutdown context */
211 struct system_shutdown_ctx system_shutdown;
212 };
213
214 /*
215 * Power domain module events
216 */
217
218 /* Power module event indexes */
219 enum pd_event_idx {
220 PD_EVENT_IDX_RESET = MOD_PD_PUBLIC_EVENT_IDX_COUNT,
221 PD_EVENT_IDX_REPORT_POWER_STATE_TRANSITION,
222 PD_EVENT_IDX_SYSTEM_SUSPEND,
223 PD_EVENT_IDX_SYSTEM_SHUTDOWN,
224 PD_EVENT_COUNT
225 };
226
227 /* Standard parameter of a response event */
228 struct pd_response {
229 /* Status of the event processing */
230 int status;
231 };
232
233 /*
234 * MOD_PD_PUBLIC_EVENT_IDX_SET_STATE
235 * Parameters of the set state request event
236 */
237 struct pd_set_state_request {
238 /*
239 * The composite state that defines the power state that the power domain,
240 * target of the request, has to be put into and possibly the power states
241 * the ancestors of the power domain have to be put into.
242 */
243 uint32_t composite_state;
244 };
245
246 /*
247 * PD_EVENT_IDX_REPORT_POWER_STATE_TRANSITION
248 * Parameters of the power state transition report event
249 */
250 struct pd_power_state_transition_report {
251 /* The new power state of the power domain */
252 uint32_t state;
253 };
254
255 /*
256 * PD_EVENT_IDX_SYSTEM_SUSPEND
257 * Parameters of the system suspend request event
258 */
259 struct pd_system_suspend_request {
260 /* System suspend state, platform specific */
261 unsigned int state;
262 };
263
264 /*
265 * PD_EVENT_IDX_SYSTEM_SHUTDOWN
266 * Parameters of the system shutdown request event
267 */
268 struct pd_system_shutdown_request {
269 /* System shutdown type */
270 enum mod_pd_system_shutdown system_shutdown;
271 };
272
273 /* Mask of the core composite states */
274 static const uint32_t core_composite_state_mask_table[] = {
275 MOD_PD_CS_STATE_MASK << MOD_PD_CS_LEVEL_0_STATE_SHIFT,
276 MOD_PD_CS_STATE_MASK << MOD_PD_CS_LEVEL_1_STATE_SHIFT,
277 MOD_PD_CS_STATE_MASK << MOD_PD_CS_LEVEL_2_STATE_SHIFT,
278 MOD_PD_CS_STATE_MASK << MOD_PD_CS_LEVEL_3_STATE_SHIFT,
279 };
280
281 /*
282 * Internal variables
283 */
284 static struct mod_pd_mod_ctx mod_pd_ctx;
285
286 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
287 static const char driver_error_msg[] = "[PD] Driver error %s (%d) in %s @%d";
288
289 static const char * const default_state_name_table[] = {
290 "OFF", "ON", "SLEEP", "3", "4", "5", "6", "7",
291 "8", "9", "10", "11", "12", "13", "14", "15"
292 };
293 #endif
294
295 /*
296 * Utility functions
297 */
298
299 /* State related utility functions */
is_valid_state(const struct pd_ctx * pd,unsigned int state)300 static bool is_valid_state(const struct pd_ctx *pd, unsigned int state)
301 {
302 return (state < MOD_PD_STATE_COUNT_MAX) &&
303 ((pd->valid_state_mask & ((uint32_t)1 << state)) != (uint32_t)0);
304 }
305
normalize_state(unsigned int state)306 static unsigned int normalize_state(unsigned int state)
307 {
308 enum mod_pd_state state_type = (enum mod_pd_state)state;
309
310 switch (state_type) {
311 case MOD_PD_STATE_OFF:
312 return (MOD_PD_STATE_COUNT_MAX + 1);
313
314 case MOD_PD_STATE_SLEEP:
315 return MOD_PD_STATE_COUNT_MAX;
316
317 default:
318 return state;
319 }
320 }
321
is_deeper_state(unsigned int state,unsigned int state_to_compare_to)322 static bool is_deeper_state(unsigned int state,
323 unsigned int state_to_compare_to)
324 {
325 return normalize_state(state) > normalize_state(state_to_compare_to);
326 }
327
is_shallower_state(unsigned int state,unsigned int state_to_compare_to)328 static bool is_shallower_state(unsigned int state,
329 unsigned int state_to_compare_to)
330 {
331 return normalize_state(state) < normalize_state(state_to_compare_to);
332 }
333
is_allowed_by_child(const struct pd_ctx * child,unsigned int parent_state,unsigned int child_state)334 static bool is_allowed_by_child(const struct pd_ctx *child,
335 unsigned int parent_state, unsigned int child_state)
336 {
337 if (parent_state >= child->allowed_state_mask_table_size) {
338 return false;
339 }
340
341 return (
342 (child->allowed_state_mask_table[parent_state] &
343 ((uint32_t)1 << child_state)) != (uint32_t)0);
344 }
345
is_allowed_by_children(const struct pd_ctx * pd,unsigned int state)346 static bool is_allowed_by_children(const struct pd_ctx *pd, unsigned int state)
347 {
348 const struct pd_ctx *child = NULL;
349 struct fwk_slist *c_node = NULL;
350
351 FWK_LIST_FOR_EACH(
352 &pd->children_list, c_node, struct pd_ctx, child_node, child)
353 {
354 if (!is_allowed_by_child(child, state, child->requested_state)) {
355 return false;
356 }
357 }
358
359 return true;
360 }
361
362 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
get_state_name(const struct pd_ctx * pd,unsigned int state)363 static const char *get_state_name(const struct pd_ctx *pd, unsigned int state)
364 {
365 static char const unknown_name[] = "Unknown";
366
367 if (state < pd->config->state_name_table_size) {
368 return pd->config->state_name_table[state];
369 } else if (state < FWK_ARRAY_SIZE(default_state_name_table)) {
370 return default_state_name_table[state];
371 } else {
372 return unknown_name;
373 }
374 }
375 #endif
376
number_of_bits_to_shift(uint32_t mask)377 static unsigned int number_of_bits_to_shift(uint32_t mask)
378 {
379 unsigned int num_bits = 0;
380
381 if (mask == (uint32_t)0) {
382 return 0;
383 }
384
385 while ((mask & (uint32_t)1) == (uint32_t)0) {
386 mask = mask >> 1;
387 num_bits++;
388 }
389
390 return num_bits;
391 }
392
393 /* Functions related to a composite state */
get_level_state_from_composite_state(const uint32_t * table,uint32_t composite_state,int level)394 static unsigned int get_level_state_from_composite_state(
395 const uint32_t *table,
396 uint32_t composite_state,
397 int level)
398 {
399 uint32_t mask = table[level];
400 unsigned int shift = number_of_bits_to_shift(mask);
401
402 return (composite_state & mask) >> shift;
403 }
404
get_highest_level_from_composite_state(const struct pd_ctx * pd,uint32_t composite_state)405 static int get_highest_level_from_composite_state(
406 const struct pd_ctx *pd,
407 uint32_t composite_state)
408 {
409 uint32_t state;
410 unsigned int shift, level;
411 const uint32_t *state_mask_table;
412 unsigned int table_size;
413
414 if (!pd->cs_support) {
415 return 0;
416 }
417
418 if (pd->composite_state_levels_mask) {
419 shift = number_of_bits_to_shift(pd->composite_state_levels_mask);
420 level = (pd->composite_state_levels_mask & composite_state) >> shift;
421 } else {
422 state_mask_table = pd->composite_state_mask_table;
423 table_size = (unsigned int)pd->composite_state_mask_table_size;
424
425 for (level = 0; ((level < table_size) && (pd != NULL));
426 level++, pd = pd->parent) {
427 state = get_level_state_from_composite_state(
428 state_mask_table, composite_state, (int)level);
429 if (!is_valid_state(pd, state)) {
430 break;
431 }
432 }
433 level--;
434 }
435
436 return (int)level;
437 }
438
is_valid_composite_state(struct pd_ctx * target_pd,uint32_t composite_state)439 static bool is_valid_composite_state(struct pd_ctx *target_pd,
440 uint32_t composite_state)
441 {
442 unsigned int level, highest_level;
443 unsigned int state, child_state = (unsigned int)MOD_PD_STATE_OFF;
444 struct pd_ctx *pd = target_pd;
445 struct pd_ctx *child = NULL;
446 const uint32_t *state_mask_table;
447 unsigned int table_size;
448
449 assert(target_pd != NULL);
450
451 if (!pd->cs_support) {
452 goto error;
453 }
454
455 highest_level = (unsigned int)get_highest_level_from_composite_state(
456 pd, composite_state);
457
458 state_mask_table = pd->composite_state_mask_table;
459 table_size = (unsigned int)pd->composite_state_mask_table_size;
460
461 if (highest_level >= table_size) {
462 goto error;
463 }
464
465 for (level = 0; level <= highest_level; level++) {
466 if (pd == NULL) {
467 goto error;
468 }
469
470 state = get_level_state_from_composite_state(
471 state_mask_table, composite_state, (int)level);
472
473 if (!is_valid_state(pd, state)) {
474 goto error;
475 }
476
477 if ((child != NULL) &&
478 !is_allowed_by_child(child, state, child_state)) {
479 goto error;
480 }
481
482 child = pd;
483 child_state = state;
484 pd = pd->parent;
485 }
486
487 return true;
488
489 error:
490 FWK_LOG_ERR(
491 "[PD] Invalid composite state for %s: 0x%" PRIX32,
492 fwk_module_get_element_name(target_pd->id),
493 composite_state);
494 return false;
495 }
496
497 /*
498 * Determine whether a composite state requires that the transition begins
499 * with the highest or lowest level.
500 *
501 * \param lowest_pd Target of the composite state transition request.
502 * \param uint32_t composite_state Target composite state.
503 * \retval true The power state transition must propagate upwards.
504 * \retval false The power state transition must propagate downwards.
505 */
is_upwards_transition_propagation(const struct pd_ctx * lowest_pd,uint32_t composite_state)506 static bool is_upwards_transition_propagation(const struct pd_ctx *lowest_pd,
507 uint32_t composite_state)
508 {
509 int highest_level, level;
510 const struct pd_ctx *pd;
511 unsigned int state;
512 const uint32_t *state_mask_table;
513
514 highest_level =
515 get_highest_level_from_composite_state(lowest_pd, composite_state);
516
517 if (!lowest_pd->cs_support) {
518 return is_deeper_state(composite_state, lowest_pd->requested_state);
519 }
520
521 state_mask_table = lowest_pd->composite_state_mask_table;
522
523 for (level = 0, pd = lowest_pd; (level <= highest_level) && (pd != NULL);
524 level++, pd = pd->parent) {
525 state = get_level_state_from_composite_state(
526 state_mask_table, composite_state, level);
527 if (state == pd->requested_state) {
528 continue;
529 }
530
531 return is_deeper_state(state, pd->requested_state);
532 }
533
534 return false;
535 }
536
537 /* Sub-routine of 'pd_post_init()', to build the power domain tree */
connect_pd_tree(void)538 static int connect_pd_tree(void)
539 {
540 unsigned int index;
541 struct pd_ctx *pd, *parent;
542
543 for (index = 0; index < mod_pd_ctx.pd_count; index++) {
544 pd = &mod_pd_ctx.pd_ctx_table[index];
545 if (pd->config->parent_idx >= mod_pd_ctx.pd_count) {
546 pd->parent = NULL;
547 continue;
548 }
549
550 parent = pd->parent = &mod_pd_ctx.pd_ctx_table[pd->config->parent_idx];
551 if (parent == NULL) {
552 return FWK_E_DATA;
553 }
554 fwk_list_push_tail(&parent->children_list, &pd->child_node);
555 }
556
557 return FWK_SUCCESS;
558 }
559
560 /*
561 * Check whether a transition to a given power state for a power domain is
562 * possible given the current state of its parent and children (if any).
563 *
564 * \param pd Description of the power domain to check the power state transition
565 * for.
566 * \param state Power state.
567 */
is_allowed_by_parent_and_children(struct pd_ctx * pd,unsigned int state)568 static bool is_allowed_by_parent_and_children(struct pd_ctx *pd,
569 unsigned int state)
570 {
571 struct pd_ctx *parent, *child = NULL;
572 struct fwk_slist *c_node = NULL;
573
574 parent = pd->parent;
575 if (parent != NULL) {
576 if (!is_allowed_by_child(pd, parent->current_state, state)) {
577 return false;
578 }
579 }
580
581 FWK_LIST_FOR_EACH(
582 &pd->children_list, c_node, struct pd_ctx, child_node, child)
583 {
584 if (!is_allowed_by_child(child, state, child->current_state)) {
585 return false;
586 }
587 }
588
589 return true;
590 }
591
592 #ifdef BUILD_HAS_NOTIFICATION
593 /*
594 * Check whether a power state pre-transition notification must be sent.
595 *
596 * \param pd Description of the power domain
597 * \param state Power state the power domain has to transit to
598 *
599 * \retval true A power state pre-transition notification must be sent.
600 * \retval false A power state pre-transition notification doesn't have to be
601 * sent.
602 */
check_power_state_pre_transition_notification(struct pd_ctx * pd,unsigned int state)603 static bool check_power_state_pre_transition_notification(struct pd_ctx *pd,
604 unsigned int state)
605 {
606 if ((state == pd->power_state_pre_transition_notification_ctx.state) &&
607 pd->power_state_pre_transition_notification_ctx.valid) {
608 return (pd->power_state_pre_transition_notification_ctx.response_status
609 != FWK_SUCCESS);
610 }
611
612 return true;
613 }
614 #endif /* BUILD_HAS_NOTIFICATION */
615
616 /*
617 * Initiate a power state pre-transition notification if necessary.
618 *
619 * \param pd Description of the power domain to initiate the notification
620 * for.
621 *
622 * \retval true Waiting for notification responses.
623 * \retval false Not waiting for any notification response.
624 */
initiate_power_state_pre_transition_notification(struct pd_ctx * pd)625 static bool initiate_power_state_pre_transition_notification(struct pd_ctx *pd)
626 {
627 #ifdef BUILD_HAS_NOTIFICATION
628 unsigned int state;
629 struct fwk_event notification_event = {
630 .id = mod_pd_notification_id_power_state_pre_transition,
631 .response_requested = true,
632 .source_id = FWK_ID_NONE
633 };
634 struct mod_pd_power_state_pre_transition_notification_params *params;
635 int status;
636
637 if (pd->config->disable_state_transition_notifications == true) {
638 return false;
639 }
640
641 state = pd->requested_state;
642 if (!check_power_state_pre_transition_notification(pd, state)) {
643 return false;
644 }
645
646 /*
647 * If still waiting for some responses on the previous power state
648 * pre-transition notification, wait for them before to issue the next one.
649 */
650 if (pd->power_state_pre_transition_notification_ctx.pending_responses !=
651 0) {
652 return true;
653 }
654
655 params = (struct mod_pd_power_state_pre_transition_notification_params *)
656 notification_event.params;
657 params->current_state = pd->current_state;
658 params->target_state = state;
659
660 notification_event.source_id = pd->id;
661 status = fwk_notification_notify(
662 ¬ification_event,
663 &pd->power_state_pre_transition_notification_ctx.pending_responses);
664 if (status != FWK_SUCCESS) {
665 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
666 }
667
668 pd->power_state_pre_transition_notification_ctx.state = state;
669 pd->power_state_pre_transition_notification_ctx.response_status =
670 FWK_SUCCESS;
671 pd->power_state_pre_transition_notification_ctx.valid = true;
672
673 return (pd->power_state_pre_transition_notification_ctx.pending_responses
674 != 0);
675 #else
676 return false;
677 #endif
678 }
679
680 /*
681 * Initiate the transition to a power state for a power domain.
682 *
683 * \param pd Description of the power domain to initiate the state transition
684 * for.
685 *
686 * \retval ::FWK_SUCCESS The power state transition was initiated.
687 * \retval ::FWK_E_DEVICE The power state transition was denied by the driver.
688 * \return One of the other driver-defined error codes.
689 */
initiate_power_state_transition(struct pd_ctx * pd)690 static int initiate_power_state_transition(struct pd_ctx *pd)
691 {
692 int status;
693 unsigned int state = pd->requested_state;
694
695 if ((pd->driver_api->deny != NULL) &&
696 pd->driver_api->deny(pd->driver_id, state)) {
697 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_DEBUG
698 FWK_LOG_DEBUG(
699 "[PD] Transition of %s to state <%s> denied by driver",
700 fwk_module_get_element_name(pd->id),
701 get_state_name(pd, state));
702 #endif
703 return FWK_E_DEVICE;
704 }
705
706 status = pd->driver_api->set_state(pd->driver_id, state);
707
708 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_DEBUG
709 if (status == FWK_SUCCESS) {
710 FWK_LOG_DEBUG(
711 "[PD] Transition of %s from <%s> to <%s> succeeded",
712 fwk_module_get_element_name(pd->id),
713 get_state_name(pd, pd->state_requested_to_driver),
714 get_state_name(pd, state));
715 }
716 #endif
717
718 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
719 if (status != FWK_SUCCESS) {
720 FWK_LOG_ERR(
721 "[PD] Transition of %s from <%s> to <%s> failed: %s",
722 fwk_module_get_element_name(pd->id),
723 get_state_name(pd, pd->state_requested_to_driver),
724 get_state_name(pd, state),
725 fwk_status_str(status));
726 }
727 #endif
728
729 pd->state_requested_to_driver = state;
730
731 return status;
732 }
733
734 /*
735 * Respond to a request.
736 *
737 * \param pd Description of the power domain in charge of the response
738 * \param resp_status Response status
739 */
respond(struct pd_ctx * pd,int resp_status)740 static void respond(struct pd_ctx *pd, int resp_status)
741 {
742 int status;
743 struct fwk_event resp_event;
744 const struct pd_set_state_request *req_params =
745 (struct pd_set_state_request *)(&resp_event.params);
746 struct pd_set_state_response *resp_params =
747 (struct pd_set_state_response *)(&resp_event.params);
748
749 if (!pd->response.pending) {
750 return;
751 }
752
753 status = fwk_get_delayed_response(pd->id, pd->response.cookie, &resp_event);
754 pd->response.pending = false;
755
756 if (status != FWK_SUCCESS) {
757 return;
758 }
759
760 resp_params->composite_state = req_params->composite_state;
761 resp_params->status = resp_status;
762
763 status = fwk_put_event(&resp_event);
764 if (status != FWK_SUCCESS) {
765 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
766 }
767 }
768
769 /*
770 * Process a 'set state' request
771 *
772 * \param lowest_pd Description of the target of the 'set state' request
773 * \param req_params Parameters of the 'set state' request
774 * \param [out] Response event
775 */
process_set_state_request(struct pd_ctx * lowest_pd,const struct fwk_event * event,struct fwk_event * resp_event)776 static void process_set_state_request(
777 struct pd_ctx *lowest_pd,
778 const struct fwk_event *event,
779 struct fwk_event *resp_event)
780 {
781 int status;
782 struct pd_set_state_request *req_params;
783 struct pd_set_state_response *resp_params;
784 uint32_t composite_state;
785 bool up, first_power_state_transition_initiated, composite_state_operation;
786 unsigned int lowest_level, highest_level, level;
787 unsigned int nb_pds, pd_index, state;
788 struct pd_ctx *pd, *pd_in_charge_of_response;
789 const struct pd_ctx *parent;
790 const uint32_t *state_mask_table = NULL;
791
792 req_params = (struct pd_set_state_request *)event->params;
793 resp_params = (struct pd_set_state_response *)resp_event->params;
794 pd_in_charge_of_response = NULL;
795 first_power_state_transition_initiated = false;
796
797 /* A set state request cancels the completion of system suspend. */
798 mod_pd_ctx.system_suspend.last_core_off_ongoing = false;
799
800 composite_state = req_params->composite_state;
801 up = is_upwards_transition_propagation(lowest_pd, composite_state);
802
803 /*
804 * It has already been tested as part of the composite state validation that
805 * 'highest_level >= lowest_level' and 'highest_level' is lower
806 * than the highest power level.
807 */
808 lowest_level = 0;
809 highest_level = (unsigned int)get_highest_level_from_composite_state(
810 lowest_pd, composite_state);
811 nb_pds = highest_level + 1U;
812
813 status = FWK_SUCCESS;
814 pd = lowest_pd;
815
816 composite_state_operation = pd->cs_support;
817 if (composite_state_operation) {
818 state_mask_table = pd->composite_state_mask_table;
819 }
820
821 for (pd_index = 0; pd_index < nb_pds; pd_index++, pd = pd->parent) {
822 if (up) {
823 level = pd_index;
824 } else {
825 /*
826 * When walking down the power domain tree, get the context of the
827 * next power domain to process as well as its level.
828 */
829 pd = lowest_pd;
830 for (level = lowest_level; level < (highest_level - pd_index);
831 level++) {
832 pd = pd->parent;
833 }
834 }
835
836 if (composite_state_operation) {
837 state = get_level_state_from_composite_state(
838 state_mask_table, composite_state, (int)level);
839 } else {
840 state = composite_state;
841 }
842
843 if (state == pd->requested_state) {
844 continue;
845 }
846
847 /*
848 * Check that the requested power state is compatible with the states
849 * currently requested for the parent and children of the power domain.
850 */
851 parent = pd->parent;
852 if ((parent != NULL) &&
853 (!is_allowed_by_child(pd, parent->requested_state, state))) {
854 status = FWK_E_PWRSTATE;
855 break;
856 }
857
858 if (!is_allowed_by_children(pd, state)) {
859 continue;
860 }
861
862 /*
863 * A new valid power state is requested for the power domain. Send any
864 * pending response concerning the previous requested power state.
865 */
866 pd->requested_state = state;
867 pd->power_state_pre_transition_notification_ctx.valid = false;
868 respond(pd, FWK_E_OVERWRITTEN);
869
870 if (pd->state_requested_to_driver == state) {
871 continue;
872 }
873
874 /*
875 * The driver must be called thus the processing of the set state
876 * request is going to be asynchronous. Assign the responsibility of
877 * the response to the request to the power domain. If there is no
878 * need for a driver call for the ancestors or descendants of the power
879 * domain as part of the processing of the requested composite state,
880 * the response to the request will be sent when the transition to the
881 * new requested power state is completed.
882 */
883 pd_in_charge_of_response = pd;
884
885 /*
886 * If a power state transition has already been initiated for an
887 * ancestor or descendant, we don't initiate the power state transition
888 * now. It will be initiated on completion of the transition of one
889 * of its ancestor or descendant.
890 */
891 if (first_power_state_transition_initiated) {
892 continue;
893 }
894
895 /*
896 * If the parent or a child is not currently in a power state
897 * compatible with the new requested state for the power domain, do not
898 * initiate the transition now as well. It will be initiated when the
899 * parent and the children are in a proper state.
900 */
901 if (!is_allowed_by_parent_and_children(pd, state)) {
902 continue;
903 }
904
905 /*
906 * Defer the power state transition if power state pre-transition
907 * notification responses need to be waited for.
908 */
909 if (initiate_power_state_pre_transition_notification(pd)) {
910 continue;
911 }
912
913 status = initiate_power_state_transition(pd);
914 if (status != FWK_SUCCESS) {
915 /*
916 * If the power state transition failed, then this power domain is
917 * no longer in charge to delay the response.
918 */
919 pd_in_charge_of_response = NULL;
920 break;
921 }
922
923 first_power_state_transition_initiated = true;
924 }
925
926 if (!event->response_requested) {
927 return;
928 }
929
930 if (pd_in_charge_of_response != NULL) {
931 resp_event->is_delayed_response = true;
932 resp_event->source_id = pd_in_charge_of_response->id;
933 pd_in_charge_of_response->response.pending = true;
934 pd_in_charge_of_response->response.cookie = resp_event->cookie;
935 } else {
936 resp_params->status = status;
937 resp_params->composite_state = composite_state;
938 }
939 }
940
941 /*
942 * Complete a system suspend
943 *
944 * Following the shutdown of the last standing core put all of its ancestors
945 * in the MOD_PD_STATE_OFF state but the system power domain which is put
946 * into the state that has been asked for.
947 *
948 * target_pd Description of the power domain target of the 'set composite state'
949 * request to suspend the system in the desired state.
950 */
complete_system_suspend(struct pd_ctx * target_pd)951 static int complete_system_suspend(struct pd_ctx *target_pd)
952 {
953 unsigned int level;
954 unsigned int shift, composite_state = 0;
955 struct pd_ctx *pd = target_pd;
956 struct fwk_event event, resp_event;
957 struct pd_set_state_request *event_params =
958 (struct pd_set_state_request *)event.params;
959 struct pd_set_state_response *resp_params =
960 (struct pd_set_state_response *)(&resp_event.params);
961 const uint32_t *state_mask_table;
962 int table_size;
963
964 if (!pd->cs_support) {
965 return FWK_E_PARAM;
966 }
967
968 state_mask_table = pd->composite_state_mask_table;
969 table_size = (int)pd->composite_state_mask_table_size;
970
971 mod_pd_ctx.system_suspend.suspend_ongoing = true;
972
973 /*
974 * Traverse the PD tree bottom-up from current power domain to the top
975 * to build the composite state with MOD_PD_STATE_OFF power state for all
976 * levels but the last one.
977 */
978 level = 0U;
979 do {
980 shift = number_of_bits_to_shift(state_mask_table[level]);
981 composite_state |=
982 ((pd->parent != NULL) ? MOD_PD_STATE_OFF :
983 mod_pd_ctx.system_suspend.state)
984 << shift;
985 pd = pd->parent;
986 level++;
987 } while ((pd != NULL) && (level < (unsigned int)table_size));
988
989 /*
990 * Finally, we need to update the highest valid level in the composite
991 * state.
992 */
993 composite_state |= (--level) << MOD_PD_CS_LEVEL_SHIFT;
994
995 event = (struct fwk_event) { 0 };
996 event_params->composite_state = composite_state;
997
998 resp_event = (struct fwk_event) { 0 };
999
1000 process_set_state_request(target_pd, &event, &resp_event);
1001
1002 return resp_params->status;
1003 }
1004
1005 /*
1006 * Process a 'get state' request.
1007 *
1008 * pd Description of the target of the 'get state' request
1009 * state the required state to be filled in
1010 */
process_get_state_request(struct pd_ctx * pd,unsigned int * state)1011 static void process_get_state_request(struct pd_ctx *pd, unsigned int *state)
1012 {
1013 unsigned int level = 0U;
1014 struct pd_ctx *const base_pd = pd;
1015 unsigned int composite_state = 0U;
1016 uint32_t shift;
1017 const uint32_t *state_mask_table;
1018 int table_size, cs_idx = 0;
1019
1020 if (!pd->cs_support) {
1021 *state = pd->current_state;
1022 } else {
1023 state_mask_table = pd->composite_state_mask_table;
1024 table_size = (int)pd->composite_state_mask_table_size;
1025
1026 /*
1027 * Traverse the PD tree bottom-up from current power domain to the top,
1028 * collecting node's states and placing them in the correct position in
1029 * the composite state.
1030 */
1031 do {
1032 shift = number_of_bits_to_shift(state_mask_table[cs_idx]);
1033 composite_state |= pd->current_state << shift;
1034 pd = pd->parent;
1035 cs_idx++;
1036 level++;
1037 } while (pd != NULL && cs_idx < table_size);
1038
1039 /*
1040 * Finally, we need to update the highest valid level in
1041 * the composite state.
1042 */
1043 if (base_pd->composite_state_levels_mask) {
1044 shift =
1045 number_of_bits_to_shift(base_pd->composite_state_levels_mask);
1046 composite_state |= (--level) << shift;
1047 }
1048
1049 *state = composite_state;
1050 }
1051 }
1052
1053 /*
1054 * Process a 'reset' request.
1055 *
1056 * pd Description of the target of the 'reset' request
1057 * resp_params Parameters of the 'reset' request response to be filled in
1058 */
process_reset_request(struct pd_ctx * pd,struct pd_response * resp_params)1059 static void process_reset_request(struct pd_ctx *pd,
1060 struct pd_response *resp_params)
1061 {
1062 int status;
1063 struct pd_ctx *child = NULL;
1064 struct fwk_slist *c_node = NULL;
1065
1066 status = FWK_E_PWRSTATE;
1067 if (pd->requested_state == MOD_PD_STATE_OFF) {
1068 goto exit;
1069 }
1070
1071 FWK_LIST_FOR_EACH(
1072 &pd->children_list, c_node, struct pd_ctx, child_node, child)
1073 {
1074 if ((child->requested_state != MOD_PD_STATE_OFF) ||
1075 (child->current_state != MOD_PD_STATE_OFF)) {
1076 goto exit;
1077 }
1078 }
1079
1080 status = pd->driver_api->reset(pd->driver_id);
1081
1082 exit:
1083 resp_params->status = status;
1084 }
1085
1086 /*
1087 * Process a power state transition report describing a transition to a deeper
1088 * state.
1089 *
1090 * \param pd Target power domain context
1091 */
process_power_state_transition_report_deeper_state(struct pd_ctx * pd)1092 static void process_power_state_transition_report_deeper_state(
1093 struct pd_ctx *pd)
1094 {
1095 struct pd_ctx *parent = pd->parent;
1096 unsigned int requested_state;
1097 int status;
1098
1099 if (parent == NULL) {
1100 return;
1101 }
1102
1103 requested_state = parent->requested_state;
1104
1105 if (parent->state_requested_to_driver == requested_state) {
1106 return;
1107 }
1108
1109 if (!is_allowed_by_parent_and_children(parent, requested_state)) {
1110 return;
1111 }
1112
1113 if (!initiate_power_state_pre_transition_notification(parent)) {
1114 status = initiate_power_state_transition(parent);
1115 if (status != FWK_SUCCESS) {
1116 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
1117 }
1118 }
1119 }
1120
1121 /*
1122 * Process a power state transition report describing a transition to a
1123 * shallower state.
1124 *
1125 * \param pd Target power domain context
1126 */
process_power_state_transition_report_shallower_state(struct pd_ctx * pd)1127 static void process_power_state_transition_report_shallower_state(
1128 struct pd_ctx *pd)
1129 {
1130 struct pd_ctx *child = NULL;
1131 unsigned int requested_state;
1132 struct fwk_slist *c_node = NULL;
1133 int status;
1134
1135 FWK_LIST_FOR_EACH(
1136 &pd->children_list, c_node, struct pd_ctx, child_node, child)
1137 {
1138 requested_state = child->requested_state;
1139 if (child->state_requested_to_driver == requested_state) {
1140 continue;
1141 }
1142
1143 if (!is_allowed_by_parent_and_children(child, requested_state)) {
1144 return;
1145 }
1146
1147 if (!initiate_power_state_pre_transition_notification(child)) {
1148 status = initiate_power_state_transition(child);
1149 if (status != FWK_SUCCESS) {
1150 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
1151 }
1152 }
1153 }
1154 }
1155
1156 /*
1157 * Process a power state transition report
1158 *
1159 * \param pd Description of the target of the power state transition report
1160 * \param report_params Parameters of the power state transition report
1161 */
process_power_state_transition_report(struct pd_ctx * pd,const struct pd_power_state_transition_report * report_params)1162 static void process_power_state_transition_report(struct pd_ctx *pd,
1163 const struct pd_power_state_transition_report *report_params)
1164 {
1165 unsigned int new_state = report_params->state;
1166 unsigned int previous_state;
1167 #ifdef BUILD_HAS_NOTIFICATION
1168 struct fwk_event notification_event = {
1169 .id = mod_pd_notification_id_power_state_transition,
1170 .response_requested = true,
1171 .source_id = FWK_ID_NONE
1172 };
1173 struct mod_pd_power_state_transition_notification_params *params;
1174 #endif
1175 int status;
1176
1177 if (new_state == pd->requested_state) {
1178 respond(pd, FWK_SUCCESS);
1179 }
1180
1181 previous_state = pd->current_state;
1182 pd->current_state = new_state;
1183
1184 #ifdef BUILD_HAS_NOTIFICATION
1185 if (pd->power_state_transition_notification_ctx.pending_responses == 0 &&
1186 pd->config->disable_state_transition_notifications == false) {
1187 params = (struct mod_pd_power_state_transition_notification_params *)
1188 notification_event.params;
1189 params->state = new_state;
1190 pd->power_state_transition_notification_ctx.state = new_state;
1191 status = fwk_notification_notify(
1192 ¬ification_event,
1193 &pd->power_state_transition_notification_ctx.pending_responses);
1194 if (status != FWK_SUCCESS) {
1195 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
1196 }
1197 }
1198 #endif
1199
1200 if ((mod_pd_ctx.system_suspend.last_core_off_ongoing) &&
1201 (pd == mod_pd_ctx.system_suspend.last_core_pd)) {
1202 mod_pd_ctx.system_suspend.last_core_off_ongoing = false;
1203 status = complete_system_suspend(pd);
1204 if (status != FWK_SUCCESS) {
1205 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
1206 }
1207
1208 return;
1209 }
1210
1211 if (pd->parent == NULL) {
1212 /* this is the top pd (SYSTOP) */
1213 if (mod_pd_ctx.system_suspend.state != MOD_PD_STATE_ON) {
1214 /* has gone down, invalidate the system suspend ongoing */
1215 mod_pd_ctx.system_suspend.suspend_ongoing = false;
1216 }
1217 }
1218
1219 #ifdef BUILD_HAS_NOTIFICATION
1220 /*
1221 * If notifications are pending, the transition report is delayed until all
1222 * the state change notifications responses have arrived.
1223 */
1224 if (pd->power_state_transition_notification_ctx.pending_responses > 0) {
1225 /*
1226 * Save previous state which will be used once all the notifications
1227 * have arrived to continue for deeper or shallower state for the next
1228 * power domain.
1229 */
1230 pd->power_state_transition_notification_ctx.previous_state =
1231 previous_state;
1232
1233 return;
1234 }
1235 #endif
1236
1237 if (is_deeper_state(new_state, previous_state)) {
1238 process_power_state_transition_report_deeper_state(pd);
1239 } else if (is_shallower_state(new_state, previous_state)) {
1240 process_power_state_transition_report_shallower_state(pd);
1241 }
1242 }
1243
1244 /*
1245 * Process a 'system suspend' request
1246 *
1247 * req_params Parameters of the 'system suspend' request
1248 * resp_params Parameters of the 'system suspend' request response to be filled
1249 * in
1250 */
process_system_suspend_request(const struct pd_system_suspend_request * req_params,struct pd_response * resp_params)1251 static void process_system_suspend_request(
1252 const struct pd_system_suspend_request *req_params,
1253 struct pd_response *resp_params)
1254 {
1255 int status;
1256 unsigned int pd_idx;
1257 struct pd_ctx *pd;
1258 struct pd_ctx *last_core_pd = NULL;
1259 struct pd_ctx *last_cluster_pd = NULL;
1260
1261 /*
1262 * All core related power domains have to be in the MOD_PD_STATE_OFF state
1263 * but one core and its ancestors.
1264 */
1265 for (pd_idx = 0; pd_idx < mod_pd_ctx.pd_count; pd_idx++) {
1266 pd = &mod_pd_ctx.pd_ctx_table[pd_idx];
1267 if ((pd->requested_state == MOD_PD_STATE_OFF) &&
1268 (pd->current_state == MOD_PD_STATE_OFF)) {
1269 continue;
1270 }
1271
1272 if (pd->config->attributes.pd_type == MOD_PD_TYPE_CORE) {
1273 if (last_core_pd != NULL) {
1274 resp_params->status = FWK_E_STATE;
1275 return;
1276 }
1277 last_core_pd = pd;
1278 } else if (pd->config->attributes.pd_type == MOD_PD_TYPE_CLUSTER) {
1279 if (last_cluster_pd != NULL) {
1280 resp_params->status = FWK_E_STATE;
1281 return;
1282 }
1283 last_cluster_pd = pd;
1284 }
1285 }
1286
1287 if (last_core_pd == NULL) {
1288 status = complete_system_suspend(
1289 (last_cluster_pd != NULL) ? last_cluster_pd :
1290 mod_pd_ctx.system_pd_ctx);
1291 } else {
1292 status = last_core_pd->driver_api->prepare_core_for_system_suspend(
1293 last_core_pd->driver_id);
1294 if (status == FWK_SUCCESS) {
1295 mod_pd_ctx.system_suspend.last_core_off_ongoing = true;
1296
1297 mod_pd_ctx.system_suspend.last_core_pd = last_core_pd;
1298 mod_pd_ctx.system_suspend.state = req_params->state;
1299 last_core_pd->requested_state =
1300 last_core_pd->state_requested_to_driver =
1301 (unsigned int)MOD_PD_STATE_OFF;
1302 }
1303 }
1304
1305 resp_params->status = status;
1306 }
1307
perform_shutdown(enum mod_pd_system_shutdown system_shutdown,struct fwk_event * resp)1308 void perform_shutdown(
1309 enum mod_pd_system_shutdown system_shutdown,
1310 struct fwk_event *resp)
1311 {
1312 struct pd_ctx *pd;
1313 unsigned int pd_idx;
1314 fwk_id_t pd_id;
1315 int status;
1316 struct fwk_event delayed_resp;
1317 struct pd_response *resp_params;
1318 struct mod_pd_driver_api *api;
1319
1320 for (pd_idx = 0; pd_idx < mod_pd_ctx.pd_count; pd_idx++) {
1321 pd = &mod_pd_ctx.pd_ctx_table[pd_idx];
1322 pd_id = FWK_ID_ELEMENT(FWK_MODULE_IDX_POWER_DOMAIN, pd_idx);
1323 api = pd->driver_api;
1324
1325 (void)pd_id;
1326 FWK_LOG_INFO(
1327 "[PD] Shutting down %s", fwk_module_get_element_name(pd_id));
1328
1329 if (api->shutdown != NULL) {
1330 status = pd->driver_api->shutdown(pd->driver_id, system_shutdown);
1331 if (status == FWK_PENDING) {
1332 /*
1333 * Only drivers implementing shutdown API can defer request for
1334 * now.
1335 */
1336 return;
1337 }
1338 } else {
1339 if ((api->deny != NULL) &&
1340 api->deny(pd->driver_id, MOD_PD_STATE_OFF)) {
1341 status = FWK_E_DEVICE;
1342 } else {
1343 status = api->set_state(pd->driver_id, MOD_PD_STATE_OFF);
1344 }
1345 }
1346
1347 if (status != FWK_SUCCESS) {
1348 FWK_LOG_ERR(
1349 "[PD] Shutdown of %s returned %s (%d)",
1350 fwk_module_get_element_name(pd_id),
1351 fwk_status_str(status),
1352 status);
1353 } else {
1354 FWK_LOG_INFO(
1355 "[PD] %s shutdown", fwk_module_get_element_name(pd_id));
1356 }
1357
1358 pd->requested_state = pd->state_requested_to_driver =
1359 pd->current_state = (unsigned int)MOD_PD_STATE_OFF;
1360 }
1361
1362 /*
1363 * At this time, the system is already down or will be down soon.
1364 * Regardless, we tentatively send the response event to the caller, should
1365 * the system fail to complete the shutdown process, the agent may want to
1366 * be notified.
1367 */
1368 if (resp == NULL) {
1369 status = fwk_get_delayed_response(
1370 fwk_module_id_power_domain,
1371 mod_pd_ctx.system_shutdown.cookie,
1372 &delayed_resp);
1373 fwk_assert(status == FWK_SUCCESS);
1374
1375 delayed_resp.source_id = fwk_module_id_power_domain;
1376
1377 resp_params = (struct pd_response *)delayed_resp.params;
1378 resp_params->status = FWK_E_PANIC;
1379
1380 status = fwk_put_event(&delayed_resp);
1381 } else {
1382 resp_params = (struct pd_response *)resp->params;
1383 resp_params->status = FWK_E_PANIC;
1384
1385 status = fwk_put_event(resp);
1386 }
1387
1388 fwk_assert(status == FWK_SUCCESS);
1389
1390 return;
1391 }
1392
1393 /*
1394 * Process a warm reset request
1395 */
notify_warm_reset(void)1396 static int notify_warm_reset(void)
1397 {
1398 #ifdef BUILD_HAS_NOTIFICATION
1399 unsigned int count;
1400 struct fwk_event notification = {
1401 .id = mod_pd_notification_id_pre_warm_reset,
1402 .source_id = FWK_ID_MODULE_INIT(FWK_MODULE_IDX_POWER_DOMAIN),
1403 };
1404
1405 return fwk_notification_notify(¬ification, &count);
1406 #else
1407 return FWK_SUCCESS;
1408 #endif
1409 }
1410
check_and_notify_system_shutdown(enum mod_pd_system_shutdown system_shutdown)1411 static bool check_and_notify_system_shutdown(
1412 enum mod_pd_system_shutdown system_shutdown)
1413 {
1414 #ifdef BUILD_HAS_NOTIFICATION
1415 struct mod_pd_pre_shutdown_notif_params *params;
1416 int status;
1417
1418 struct fwk_event notification = {
1419 .id = mod_pd_notification_id_pre_shutdown,
1420 .source_id = fwk_module_id_power_domain,
1421 .response_requested = true
1422 };
1423
1424 params = (struct mod_pd_pre_shutdown_notif_params *)notification.params;
1425 params->system_shutdown = system_shutdown;
1426
1427 status = fwk_notification_notify(
1428 ¬ification, &mod_pd_ctx.system_shutdown.notifications_count);
1429 if (status != FWK_SUCCESS) {
1430 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
1431 }
1432
1433 return (mod_pd_ctx.system_shutdown.notifications_count != 0);
1434 #else
1435 return false;
1436 #endif
1437 }
1438
1439 /*
1440 * Process a 'system shutdown' request
1441 */
process_system_shutdown_request(const struct fwk_event * event,struct fwk_event * resp)1442 static void process_system_shutdown_request(
1443 const struct fwk_event *event,
1444 struct fwk_event *resp)
1445 {
1446 enum mod_pd_system_shutdown system_shutdown;
1447
1448 const struct pd_system_shutdown_request *req_params =
1449 (struct pd_system_shutdown_request *)event->params;
1450 struct pd_response *resp_params = (struct pd_response *)resp->params;
1451
1452 system_shutdown = req_params->system_shutdown;
1453
1454 switch (system_shutdown) {
1455 case MOD_PD_SYSTEM_WARM_RESET:
1456 resp_params->status = notify_warm_reset();
1457 break;
1458
1459 default:
1460 /* Check and send pre-shutdown notifications */
1461 if (check_and_notify_system_shutdown(system_shutdown)) {
1462 mod_pd_ctx.system_shutdown.ongoing = true;
1463 mod_pd_ctx.system_shutdown.system_shutdown = system_shutdown;
1464
1465 mod_pd_ctx.system_shutdown.cookie = event->cookie;
1466 resp->is_delayed_response = true;
1467
1468 /*
1469 * The shutdown procedure will be completed once all the
1470 * notification responses have been received.
1471 */
1472 return;
1473 }
1474
1475 perform_shutdown(system_shutdown, resp);
1476
1477 resp_params->status = FWK_E_PANIC;
1478 }
1479 }
1480
1481 /*
1482 * API functions
1483 */
1484
1485 /* Functions common to the public and restricted API */
pd_get_domain_type(fwk_id_t pd_id,enum mod_pd_type * type)1486 static int pd_get_domain_type(fwk_id_t pd_id, enum mod_pd_type *type)
1487 {
1488 struct pd_ctx *pd;
1489
1490 if (type == NULL) {
1491 return FWK_E_PARAM;
1492 }
1493
1494 if (!fwk_module_is_valid_element_id(pd_id)) {
1495 return FWK_E_PARAM;
1496 }
1497
1498 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(pd_id)];
1499
1500 *type = pd->config->attributes.pd_type;
1501
1502 return FWK_SUCCESS;
1503 }
1504
pd_get_domain_parent_id(fwk_id_t pd_id,fwk_id_t * parent_pd_id)1505 static int pd_get_domain_parent_id(fwk_id_t pd_id, fwk_id_t *parent_pd_id)
1506 {
1507 const struct pd_ctx *pd;
1508
1509 if (parent_pd_id == NULL) {
1510 return FWK_E_PARAM;
1511 }
1512
1513 if (!fwk_module_is_valid_element_id(pd_id)) {
1514 return FWK_E_PARAM;
1515 }
1516
1517 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(pd_id)];
1518
1519 *parent_pd_id = (pd->parent != NULL) ? pd->parent->id : FWK_ID_NONE;
1520
1521 return FWK_SUCCESS;
1522 }
1523
1524 /* Functions specific to the restricted API */
pd_set_state(fwk_id_t pd_id,bool response_requested,uint32_t state)1525 static int pd_set_state(fwk_id_t pd_id, bool response_requested, uint32_t state)
1526 {
1527 struct pd_ctx *pd;
1528 struct fwk_event req;
1529 struct pd_set_state_request *req_params =
1530 (struct pd_set_state_request *)(&req.params);
1531
1532 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(pd_id)];
1533
1534 if (pd->cs_support) {
1535 if (!is_valid_composite_state(pd, state)) {
1536 return FWK_E_PARAM;
1537 }
1538 } else {
1539 if (!is_valid_state(pd, state)) {
1540 return FWK_E_PARAM;
1541 }
1542 }
1543
1544 req = (struct fwk_event) {
1545 .id = FWK_ID_EVENT(FWK_MODULE_IDX_POWER_DOMAIN,
1546 MOD_PD_PUBLIC_EVENT_IDX_SET_STATE),
1547 .source_id = pd->driver_id,
1548 .target_id = pd_id,
1549 .response_requested = response_requested,
1550 };
1551
1552 req_params->composite_state = state;
1553
1554 return fwk_put_event(&req);
1555 }
1556
pd_get_state(fwk_id_t pd_id,unsigned int * state)1557 static int pd_get_state(fwk_id_t pd_id, unsigned int *state)
1558 {
1559 struct pd_ctx *pd = NULL;
1560
1561 if (state == NULL) {
1562 return FWK_E_PARAM;
1563 }
1564
1565 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(pd_id)];
1566
1567 process_get_state_request(pd, state);
1568
1569 return FWK_SUCCESS;
1570 }
1571
pd_system_suspend(unsigned int state)1572 static int pd_system_suspend(unsigned int state)
1573 {
1574 struct fwk_event req;
1575 struct pd_system_suspend_request *req_params =
1576 (struct pd_system_suspend_request *)(&req.params);
1577
1578 req = (struct fwk_event){
1579 .id = FWK_ID_EVENT(
1580 FWK_MODULE_IDX_POWER_DOMAIN, PD_EVENT_IDX_SYSTEM_SUSPEND),
1581 .target_id = fwk_module_id_power_domain,
1582 };
1583
1584 req_params->state = state;
1585
1586 return fwk_put_event(&req);
1587 }
1588
pd_system_shutdown(enum mod_pd_system_shutdown system_shutdown)1589 static int pd_system_shutdown(enum mod_pd_system_shutdown system_shutdown)
1590 {
1591 int status;
1592 struct fwk_event req;
1593 struct pd_system_shutdown_request *req_params =
1594 (struct pd_system_shutdown_request *)(&req.params);
1595
1596 req = (struct fwk_event) {
1597 .id = FWK_ID_EVENT(FWK_MODULE_IDX_POWER_DOMAIN,
1598 PD_EVENT_IDX_SYSTEM_SHUTDOWN),
1599 .target_id = fwk_module_id_power_domain,
1600 };
1601
1602 req_params->system_shutdown = system_shutdown;
1603
1604 status = fwk_put_event(&req);
1605 if (status == FWK_SUCCESS) {
1606 return FWK_PENDING;
1607 }
1608
1609 return status;
1610 }
1611
1612 /* Functions specific to the driver input API */
1613
pd_reset(fwk_id_t pd_id,bool response_requested)1614 static int pd_reset(fwk_id_t pd_id, bool response_requested)
1615 {
1616 struct fwk_event_light req;
1617 struct pd_ctx *pd;
1618
1619 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(pd_id)];
1620
1621 req = (struct fwk_event_light){
1622 .id = FWK_ID_EVENT(FWK_MODULE_IDX_POWER_DOMAIN, PD_EVENT_IDX_RESET),
1623 .source_id = pd->driver_id,
1624 .target_id = pd_id,
1625 .response_requested = response_requested,
1626 };
1627
1628 return fwk_put_event(&req);
1629 }
1630
report_power_state_transition(const struct pd_ctx * pd,unsigned int state)1631 static int report_power_state_transition(const struct pd_ctx *pd,
1632 unsigned int state)
1633 {
1634 struct fwk_event report;
1635 struct pd_power_state_transition_report *report_params =
1636 (struct pd_power_state_transition_report *)(&report.params);
1637
1638 report = (struct fwk_event){
1639 .source_id = pd->driver_id,
1640 .target_id = pd->id,
1641 .id = FWK_ID_EVENT(FWK_MODULE_IDX_POWER_DOMAIN,
1642 PD_EVENT_IDX_REPORT_POWER_STATE_TRANSITION)
1643 };
1644 report_params->state = state;
1645
1646 return fwk_put_event(&report);
1647 }
1648
pd_report_power_state_transition(fwk_id_t pd_id,unsigned int state)1649 static int pd_report_power_state_transition(fwk_id_t pd_id, unsigned int state)
1650 {
1651 const struct pd_ctx *pd =
1652 &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(pd_id)];
1653
1654 return report_power_state_transition(pd, state);
1655 }
1656
pd_get_last_core_pd_id(fwk_id_t * last_core_pd_id)1657 static int pd_get_last_core_pd_id(fwk_id_t *last_core_pd_id)
1658 {
1659 bool system_suspend_ongoing = mod_pd_ctx.system_suspend.suspend_ongoing;
1660 if (last_core_pd_id == NULL) {
1661 return FWK_E_PARAM;
1662 }
1663
1664 if (!system_suspend_ongoing) {
1665 return FWK_E_PWRSTATE;
1666 }
1667
1668 *last_core_pd_id = mod_pd_ctx.system_suspend.last_core_pd->id;
1669
1670 return FWK_SUCCESS;
1671 }
1672
1673 /* Module APIs */
1674
1675 static const struct mod_pd_public_api pd_public_api = {
1676 .get_domain_type = pd_get_domain_type,
1677 .get_domain_parent_id = pd_get_domain_parent_id,
1678 };
1679
1680 static const struct mod_pd_restricted_api pd_restricted_api = {
1681 .get_domain_type = pd_get_domain_type,
1682 .get_domain_parent_id = pd_get_domain_parent_id,
1683
1684 .set_state = pd_set_state,
1685 .get_state = pd_get_state,
1686 .reset = pd_reset,
1687 .system_suspend = pd_system_suspend,
1688 .system_shutdown = pd_system_shutdown
1689 };
1690
1691 static const struct mod_pd_driver_input_api pd_driver_input_api = {
1692 .set_state = pd_set_state,
1693 .reset = pd_reset,
1694 .report_power_state_transition = pd_report_power_state_transition,
1695 .get_last_core_pd_id = pd_get_last_core_pd_id,
1696 };
1697
1698 /*
1699 * Framework handlers
1700 */
pd_init(fwk_id_t module_id,unsigned int dev_count,const void * data)1701 static int pd_init(fwk_id_t module_id, unsigned int dev_count,
1702 const void *data)
1703 {
1704 if ((data == NULL) || (dev_count == 0)) {
1705 return FWK_E_PARAM;
1706 }
1707
1708 mod_pd_ctx.config = (struct mod_power_domain_config *)data;
1709
1710 if ((mod_pd_ctx.config->authorized_id_table == NULL) &&
1711 (mod_pd_ctx.config->authorized_id_table_size != 0)) {
1712 return FWK_E_PARAM;
1713 }
1714
1715 mod_pd_ctx.pd_ctx_table = fwk_mm_calloc(dev_count, sizeof(struct pd_ctx));
1716
1717 mod_pd_ctx.pd_count = dev_count;
1718 mod_pd_ctx.system_pd_ctx = &mod_pd_ctx.pd_ctx_table[dev_count - 1];
1719
1720 return FWK_SUCCESS;
1721 }
1722
pd_power_domain_init(fwk_id_t pd_id,unsigned int unused,const void * config)1723 static int pd_power_domain_init(fwk_id_t pd_id, unsigned int unused,
1724 const void *config)
1725 {
1726 const struct mod_power_domain_element_config *pd_config =
1727 (const struct mod_power_domain_element_config *)config;
1728 struct pd_ctx *pd;
1729 unsigned int state;
1730
1731 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(pd_id)];
1732
1733 fwk_list_init(&pd->children_list);
1734
1735 if (pd_config->attributes.pd_type >= MOD_PD_TYPE_COUNT) {
1736 return FWK_E_PARAM;
1737 }
1738
1739 if ((pd_config->allowed_state_mask_table == NULL) ||
1740 (pd_config->allowed_state_mask_table_size == 0)) {
1741 return FWK_E_PARAM;
1742 }
1743
1744 pd->allowed_state_mask_table = pd_config->allowed_state_mask_table;
1745 pd->allowed_state_mask_table_size =
1746 pd_config->allowed_state_mask_table_size;
1747
1748 for (state = 0; state < pd->allowed_state_mask_table_size; state++) {
1749 pd->valid_state_mask |= pd->allowed_state_mask_table[state];
1750 }
1751
1752 if ((pd_config->composite_state_mask_table != NULL) &&
1753 (pd_config->composite_state_mask_table_size > 0)) {
1754 pd->composite_state_mask_table = pd_config->composite_state_mask_table;
1755 pd->composite_state_mask_table_size =
1756 pd_config->composite_state_mask_table_size;
1757 pd->composite_state_levels_mask =
1758 pd_config->composite_state_levels_mask;
1759 pd->cs_support = true;
1760
1761 } else if (pd_config->attributes.pd_type == MOD_PD_TYPE_CORE) {
1762 pd->composite_state_mask_table = core_composite_state_mask_table;
1763 pd->composite_state_mask_table_size =
1764 FWK_ARRAY_SIZE(core_composite_state_mask_table);
1765 pd->composite_state_levels_mask = MOD_PD_CS_STATE_MASK
1766 << MOD_PD_CS_LEVEL_SHIFT;
1767 pd->cs_support = true;
1768
1769 } else {
1770 pd->cs_support = false;
1771 }
1772
1773 pd->id = pd_id;
1774 pd->config = pd_config;
1775
1776 return FWK_SUCCESS;
1777 }
1778
pd_post_init(fwk_id_t module_id)1779 static int pd_post_init(fwk_id_t module_id)
1780 {
1781 int status;
1782
1783 status = connect_pd_tree();
1784 if (status != FWK_SUCCESS) {
1785 return status;
1786 }
1787
1788 return FWK_SUCCESS;
1789 }
1790
pd_bind(fwk_id_t id,unsigned int round)1791 static int pd_bind(fwk_id_t id, unsigned int round)
1792 {
1793 int status;
1794 struct pd_ctx *pd;
1795 const struct mod_power_domain_element_config *config;
1796 struct mod_pd_driver_api *driver_api = NULL;
1797
1798 /* Nothing to do but during the first round of calls */
1799 if (round != 0) {
1800 return FWK_SUCCESS;
1801 }
1802
1803 if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
1804 return FWK_SUCCESS;
1805 }
1806
1807 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(id)];
1808 config = pd->config;
1809
1810 status = fwk_module_bind(config->driver_id, config->api_id, &driver_api);
1811 if (status != FWK_SUCCESS) {
1812 return status;
1813 }
1814
1815 pd->driver_id = config->driver_id;
1816 if ((driver_api->set_state == NULL) || (driver_api->get_state == NULL) ||
1817 (driver_api->reset == NULL) ||
1818 ((config->attributes.pd_type == MOD_PD_TYPE_CORE) &&
1819 (driver_api->prepare_core_for_system_suspend == NULL))) {
1820 return FWK_E_PARAM;
1821 }
1822
1823 pd->driver_api = driver_api;
1824
1825 return FWK_SUCCESS;
1826 }
1827
pd_start(fwk_id_t id)1828 static int pd_start(fwk_id_t id)
1829 {
1830 int status;
1831 int index;
1832 struct pd_ctx *pd;
1833 unsigned int state;
1834
1835 /* Nothing to do for elements */
1836 if (fwk_module_is_valid_element_id(id)) {
1837 return FWK_SUCCESS;
1838 }
1839
1840 for (index = (int)(mod_pd_ctx.pd_count - 1); index >= 0; index--) {
1841 pd = &mod_pd_ctx.pd_ctx_table[index];
1842 pd->requested_state = (unsigned int)MOD_PD_STATE_OFF;
1843 pd->state_requested_to_driver = (unsigned int)MOD_PD_STATE_OFF;
1844 pd->current_state = (unsigned int)MOD_PD_STATE_OFF;
1845
1846 /*
1847 * If the power domain parent is powered down, don't call the driver
1848 * to get the power domain state as the power domain registers may
1849 * not be accessible. That way, the drivers don't have to care about
1850 * this case.
1851 */
1852 if ((pd->parent != NULL) &&
1853 (pd->parent->requested_state == MOD_PD_STATE_OFF)) {
1854 continue;
1855 }
1856
1857 /* Get the current power state of the power domain from its driver. */
1858 status = pd->driver_api->get_state(pd->driver_id, &state);
1859 if (status != FWK_SUCCESS) {
1860 #if FWK_LOG_LEVEL <= FWK_LOG_LEVEL_ERROR
1861 FWK_LOG_ERR(
1862 driver_error_msg,
1863 fwk_status_str(status),
1864 status,
1865 __func__,
1866 __LINE__);
1867 #endif
1868 } else {
1869 pd->requested_state = pd->state_requested_to_driver = state;
1870
1871 if (state == MOD_PD_STATE_OFF) {
1872 continue;
1873 }
1874
1875 status = report_power_state_transition(pd, state);
1876 if (status != FWK_SUCCESS) {
1877 FWK_LOG_DEBUG("[PD] %s @%d", __func__, __LINE__);
1878 }
1879 }
1880 }
1881
1882 return FWK_SUCCESS;
1883 }
1884
pd_process_bind_request(fwk_id_t source_id,fwk_id_t target_id,fwk_id_t api_id,const void ** api)1885 static int pd_process_bind_request(fwk_id_t source_id, fwk_id_t target_id,
1886 fwk_id_t api_id, const void **api)
1887 {
1888 struct pd_ctx *pd;
1889 unsigned int id_idx;
1890
1891 enum mod_pd_api_idx api_id_type =
1892 (enum mod_pd_api_idx)fwk_id_get_api_idx(api_id);
1893
1894 switch (api_id_type) {
1895 case MOD_PD_API_IDX_PUBLIC:
1896 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_MODULE)) {
1897 return FWK_E_ACCESS;
1898 }
1899 *api = &pd_public_api;
1900 break;
1901
1902 case MOD_PD_API_IDX_RESTRICTED:
1903 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_MODULE)) {
1904 return FWK_E_ACCESS;
1905 }
1906 if (mod_pd_ctx.config->authorized_id_table_size == 0) {
1907 *api = &pd_restricted_api;
1908 return FWK_SUCCESS;
1909 }
1910 for (id_idx = 0;
1911 id_idx < mod_pd_ctx.config->authorized_id_table_size;
1912 id_idx++) {
1913
1914 if (fwk_id_is_equal(source_id,
1915 mod_pd_ctx.config->authorized_id_table[id_idx])) {
1916 *api = &pd_restricted_api;
1917 return FWK_SUCCESS;
1918 }
1919 }
1920 return FWK_E_ACCESS;
1921
1922 case MOD_PD_API_IDX_DRIVER_INPUT:
1923 if (!fwk_id_is_type(target_id, FWK_ID_TYPE_ELEMENT)) {
1924 return FWK_E_ACCESS;
1925 }
1926 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(target_id)];
1927 if (!fwk_id_is_equal(source_id, pd->driver_id)) {
1928 return FWK_E_ACCESS;
1929 }
1930 *api = &pd_driver_input_api;
1931 break;
1932
1933 default:
1934 return FWK_E_PARAM;
1935 }
1936
1937 return FWK_SUCCESS;
1938 }
1939
pd_process_event(const struct fwk_event * event,struct fwk_event * resp)1940 static int pd_process_event(const struct fwk_event *event,
1941 struct fwk_event *resp)
1942 {
1943 struct pd_ctx *pd = NULL;
1944
1945 if (fwk_id_is_type(event->target_id, FWK_ID_TYPE_ELEMENT)) {
1946 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(event->target_id)];
1947 }
1948
1949 switch (fwk_id_get_event_idx(event->id)) {
1950 case (unsigned int)MOD_PD_PUBLIC_EVENT_IDX_SET_STATE:
1951 fwk_assert(pd != NULL);
1952
1953 process_set_state_request(pd, event, resp);
1954
1955 return FWK_SUCCESS;
1956
1957 case (unsigned int)PD_EVENT_IDX_RESET:
1958 fwk_assert(pd != NULL);
1959
1960 process_reset_request(pd, (struct pd_response *)resp->params);
1961
1962 return FWK_SUCCESS;
1963
1964 case (unsigned int)PD_EVENT_IDX_REPORT_POWER_STATE_TRANSITION:
1965 fwk_assert(pd != NULL);
1966
1967 process_power_state_transition_report(pd,
1968 (struct pd_power_state_transition_report *)event->params);
1969
1970 return FWK_SUCCESS;
1971
1972 case (unsigned int)PD_EVENT_IDX_SYSTEM_SUSPEND:
1973 process_system_suspend_request(
1974 (struct pd_system_suspend_request *)event->params,
1975 (struct pd_response *)resp->params);
1976
1977 return FWK_SUCCESS;
1978
1979 case (unsigned int)PD_EVENT_IDX_SYSTEM_SHUTDOWN:
1980 process_system_shutdown_request(event, resp);
1981
1982 return FWK_SUCCESS;
1983
1984 default:
1985 FWK_LOG_ERR(
1986 "[PD] Invalid power state request: %s.", FWK_ID_STR(event->id));
1987
1988 return FWK_E_PARAM;
1989 }
1990 }
1991
1992 #ifdef BUILD_HAS_NOTIFICATION
process_pre_shutdown_notification_response(void)1993 static int process_pre_shutdown_notification_response(void)
1994 {
1995 if (mod_pd_ctx.system_shutdown.ongoing) {
1996 mod_pd_ctx.system_shutdown.notifications_count--;
1997
1998 if (mod_pd_ctx.system_shutdown.notifications_count == 0) {
1999 /* All notifications for system shutdown have been received */
2000 perform_shutdown(mod_pd_ctx.system_shutdown.system_shutdown, NULL);
2001 }
2002 return FWK_SUCCESS;
2003 } else {
2004 return FWK_E_PARAM;
2005 }
2006 }
2007
process_power_state_pre_transition_notification_response(struct pd_ctx * pd,struct mod_pd_power_state_pre_transition_notification_resp_params * params)2008 static int process_power_state_pre_transition_notification_response(
2009 struct pd_ctx *pd,
2010 struct mod_pd_power_state_pre_transition_notification_resp_params *params)
2011 {
2012 if (pd->power_state_pre_transition_notification_ctx.pending_responses
2013 == 0) {
2014 fwk_unexpected();
2015 return FWK_E_PANIC;
2016 }
2017
2018 if (params->status != FWK_SUCCESS) {
2019 pd->power_state_pre_transition_notification_ctx.response_status =
2020 FWK_E_DEVICE;
2021 }
2022
2023 pd->power_state_pre_transition_notification_ctx.pending_responses--;
2024 if (pd->power_state_pre_transition_notification_ctx.pending_responses !=
2025 0) {
2026 return FWK_SUCCESS;
2027 }
2028
2029 if (pd->power_state_pre_transition_notification_ctx.valid == true) {
2030 /*
2031 * All the notification responses have been received, the requested
2032 * state for the power domain has not changed in the
2033 * meantime and all the notified entities agreed on the power state
2034 * transition, proceed with it.
2035 */
2036 if (pd->power_state_pre_transition_notification_ctx.response_status ==
2037 FWK_SUCCESS) {
2038 return initiate_power_state_transition(pd);
2039 }
2040 } else {
2041 /*
2042 * All the notification responses have been received but the
2043 * requested state for the power domain has changed, start the
2044 * processings for the new requested state.
2045 */
2046 if ((pd->requested_state == pd->state_requested_to_driver) ||
2047 (!is_allowed_by_parent_and_children(pd, pd->requested_state))) {
2048 return FWK_SUCCESS;
2049 }
2050
2051 if (!initiate_power_state_pre_transition_notification(pd)) {
2052 return initiate_power_state_transition(pd);
2053 }
2054 }
2055
2056 return FWK_SUCCESS;
2057 }
2058
process_power_state_transition_notification_response(struct pd_ctx * pd)2059 static int process_power_state_transition_notification_response(
2060 struct pd_ctx *pd)
2061 {
2062 struct fwk_event notification_event = { 0 };
2063 struct mod_pd_power_state_transition_notification_params *params;
2064
2065 if (pd->power_state_transition_notification_ctx.pending_responses == 0) {
2066 fwk_unexpected();
2067 return FWK_E_PANIC;
2068 }
2069
2070 pd->power_state_transition_notification_ctx.pending_responses--;
2071 if (pd->power_state_transition_notification_ctx.pending_responses != 0) {
2072 return FWK_SUCCESS;
2073 }
2074
2075 if (pd->power_state_transition_notification_ctx.state ==
2076 pd->current_state) {
2077 /* All notifications received, complete the transition report */
2078
2079 unsigned int previous_state =
2080 pd->power_state_transition_notification_ctx.previous_state;
2081
2082 pd->power_state_transition_notification_ctx.previous_state =
2083 pd->current_state;
2084 /*
2085 * Complete the report state change now that we have all notifications
2086 */
2087 if (is_deeper_state(pd->current_state, previous_state)) {
2088 process_power_state_transition_report_deeper_state(pd);
2089 } else if (is_shallower_state(pd->current_state, previous_state)) {
2090 process_power_state_transition_report_shallower_state(pd);
2091 }
2092
2093 return FWK_SUCCESS;
2094 }
2095
2096 /*
2097 * While receiving the responses, the power state of the power domain
2098 * has changed. Send a notification for the current power state.
2099 */
2100 notification_event.id = mod_pd_notification_id_power_state_transition;
2101 notification_event.response_requested = true;
2102 notification_event.source_id = FWK_ID_NONE;
2103
2104 params = (struct mod_pd_power_state_transition_notification_params *)
2105 notification_event.params;
2106 params->state = pd->current_state;
2107
2108 pd->power_state_transition_notification_ctx.state = pd->current_state;
2109 return fwk_notification_notify(
2110 ¬ification_event,
2111 &pd->power_state_transition_notification_ctx.pending_responses);
2112 }
2113
pd_process_notification(const struct fwk_event * event,struct fwk_event * resp)2114 static int pd_process_notification(const struct fwk_event *event,
2115 struct fwk_event *resp)
2116 {
2117 struct pd_ctx *pd;
2118
2119 /* Only responses are expected. */
2120 if (!event->is_response) {
2121 fwk_unexpected();
2122 return FWK_E_SUPPORT;
2123 }
2124
2125 if (fwk_id_is_equal(event->id, mod_pd_notification_id_pre_shutdown)) {
2126 return process_pre_shutdown_notification_response();
2127 }
2128
2129 if (!fwk_module_is_valid_element_id(event->target_id)) {
2130 fwk_unexpected();
2131 return FWK_E_PARAM;
2132 }
2133
2134 pd = &mod_pd_ctx.pd_ctx_table[fwk_id_get_element_idx(event->target_id)];
2135
2136 if (fwk_id_is_equal(
2137 event->id, mod_pd_notification_id_power_state_transition)) {
2138 return process_power_state_transition_notification_response(pd);
2139 }
2140
2141 return process_power_state_pre_transition_notification_response(pd,
2142 (struct mod_pd_power_state_pre_transition_notification_resp_params *)
2143 event->params);
2144 }
2145 #endif /* BUILD_HAS_NOTIFICATION */
2146
2147 /* Module definition */
2148 const struct fwk_module module_power_domain = {
2149 .type = FWK_MODULE_TYPE_HAL,
2150 .api_count = (unsigned int)MOD_PD_API_IDX_COUNT,
2151 .event_count = (unsigned int)PD_EVENT_COUNT,
2152 #ifdef BUILD_HAS_NOTIFICATION
2153 .notification_count = (unsigned int)MOD_PD_NOTIFICATION_COUNT,
2154 #endif
2155 .init = pd_init,
2156 .element_init = pd_power_domain_init,
2157 .post_init = pd_post_init,
2158 .bind = pd_bind,
2159 .start = pd_start,
2160 .process_bind_request = pd_process_bind_request,
2161 .process_event = pd_process_event,
2162 #ifdef BUILD_HAS_NOTIFICATION
2163 .process_notification = pd_process_notification
2164 #endif
2165 };
2166