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         &notification_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             &notification_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(&notification, &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         &notification, &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         &notification_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