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  *     Framework API for the architecture layer.
9  */
10 #include <internal/fwk_module.h>
11 
12 #include <fwk_arch.h>
13 #include <fwk_assert.h>
14 
15 #include <arch_helpers.h>
16 
17 #if FWK_HAS_INCLUDE(<fmw_arch.h>)
18 #    include <fmw_arch.h>
19 #endif
20 
21 #include <internal/fwk_core.h>
22 
23 #include <fwk_io.h>
24 #include <fwk_log.h>
25 #include <fwk_module.h>
26 #include <fwk_module_idx.h>
27 #include <fwk_status.h>
28 
29 #include <string.h>
30 
31 extern int fwk_interrupt_init(const struct fwk_arch_interrupt_driver *driver);
32 
fwk_arch_interrupt_init(int (* interrupt_init_handler)(const struct fwk_arch_interrupt_driver ** driver))33 static int fwk_arch_interrupt_init(int (*interrupt_init_handler)(
34     const struct fwk_arch_interrupt_driver **driver))
35 {
36     /* Initialize interrupt management */
37     int status;
38     const struct fwk_arch_interrupt_driver *driver;
39 
40     /*
41      * Retrieve a pointer to the interrupt management driver from the
42      * architecture layer.
43      */
44     status = interrupt_init_handler(&driver);
45     if (status != FWK_SUCCESS) {
46         return FWK_E_PANIC;
47     }
48 
49     /* Initialize the interrupt management component */
50     status = fwk_interrupt_init(driver);
51     if (status != FWK_SUCCESS) {
52         return FWK_E_PANIC;
53     }
54 
55     return FWK_SUCCESS;
56 }
57 
fwk_arch_init(const struct fwk_arch_init_driver * driver)58 int fwk_arch_init(const struct fwk_arch_init_driver *driver)
59 {
60     int status;
61 
62     if (driver == NULL) {
63         return FWK_E_PARAM;
64     }
65 
66     if (driver->interrupt == NULL) {
67         return FWK_E_PARAM;
68     }
69 
70     fwk_module_init();
71 
72     status = fwk_io_init();
73     if (!fwk_expect(status == FWK_SUCCESS)) {
74         return FWK_E_PANIC;
75     }
76 
77     status = fwk_log_init();
78     if (!fwk_expect(status == FWK_SUCCESS)) {
79         return FWK_E_PANIC;
80     }
81 
82     /* Initialize interrupt management */
83     status = fwk_arch_interrupt_init(driver->interrupt);
84     if (!fwk_expect(status == FWK_SUCCESS)) {
85         return FWK_E_PANIC;
86     }
87 
88     status = fwk_module_start();
89     if (!fwk_expect(status == FWK_SUCCESS)) {
90         return FWK_E_PANIC;
91     }
92 
93     /*
94      * In case firmware running under other OS context, finish processing of
95      * any raised events/interrupts and return. Else continue to process events
96      * in a forever loop.
97      */
98 #if defined(BUILD_HAS_SUB_SYSTEM_MODE)
99     fwk_process_event_queue();
100     fwk_log_flush();
101 #else
102     __fwk_run_main_loop();
103 #endif
104 
105     return FWK_SUCCESS;
106 }
107 
fwk_arch_deinit(void)108 int fwk_arch_deinit(void)
109 {
110     int status;
111 
112     status = fwk_module_stop();
113     if (!fwk_expect(status == FWK_SUCCESS)) {
114         return FWK_E_PANIC;
115     }
116 
117     return FWK_SUCCESS;
118 }
119 
fwk_arch_suspend(void)120 void fwk_arch_suspend(void)
121 {
122     /* On some arm plaforms, wfe is supported architecturally, however
123      * implementation is erroneous. In such platforms FMW_DISABLE_ARCH_SUSPEND
124      * needs to be defined
125      */
126 #if !defined(FMW_DISABLE_ARCH_SUSPEND)
127     arch_suspend();
128 #endif
129 }
130