1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *     Interrupt management.
9  */
10 
11 #include <internal/fwk_interrupt.h>
12 
13 #include <fwk_arch.h>
14 #include <fwk_interrupt.h>
15 #include <fwk_status.h>
16 
17 #include <stdbool.h>
18 #include <stddef.h>
19 
20 static bool initialized;
21 static const struct fwk_arch_interrupt_driver *fwk_interrupt_driver;
22 
fwk_interrupt_init(const struct fwk_arch_interrupt_driver * driver)23 int fwk_interrupt_init(const struct fwk_arch_interrupt_driver *driver)
24 {
25     /* Validate driver by checking that all function pointers are non-null */
26     if (driver == NULL) {
27         return FWK_E_PARAM;
28     }
29     if (driver->global_enable == NULL) {
30         return FWK_E_PARAM;
31     }
32     if (driver->global_disable == NULL) {
33         return FWK_E_PARAM;
34     }
35     if (driver->is_enabled == NULL) {
36         return FWK_E_PARAM;
37     }
38     if (driver->enable == NULL) {
39         return FWK_E_PARAM;
40     }
41     if (driver->disable == NULL) {
42         return FWK_E_PARAM;
43     }
44     if (driver->is_pending == NULL) {
45         return FWK_E_PARAM;
46     }
47     if (driver->set_pending == NULL) {
48         return FWK_E_PARAM;
49     }
50     if (driver->clear_pending == NULL) {
51         return FWK_E_PARAM;
52     }
53     if (driver->set_isr_irq == NULL) {
54         return FWK_E_PARAM;
55     }
56     if (driver->set_isr_irq_param == NULL) {
57         return FWK_E_PARAM;
58     }
59     if (driver->set_isr_nmi == NULL) {
60         return FWK_E_PARAM;
61     }
62     if (driver->set_isr_nmi_param == NULL) {
63         return FWK_E_PARAM;
64     }
65     if (driver->set_isr_fault == NULL) {
66         return FWK_E_PARAM;
67     }
68     if (driver->get_current == NULL) {
69         return FWK_E_PARAM;
70     }
71 
72     fwk_interrupt_driver = driver;
73     initialized = true;
74 
75     return FWK_SUCCESS;
76 }
77 
fwk_interrupt_is_enabled(unsigned int interrupt,bool * enabled)78 int fwk_interrupt_is_enabled(unsigned int interrupt, bool *enabled)
79 {
80     if (!initialized) {
81         return FWK_E_INIT;
82     }
83 
84     if (enabled == NULL) {
85         return FWK_E_PARAM;
86     }
87 
88     return fwk_interrupt_driver->is_enabled(interrupt, enabled);
89 }
90 
fwk_interrupt_enable(unsigned int interrupt)91 int fwk_interrupt_enable(unsigned int interrupt)
92 {
93     if (!initialized) {
94         return FWK_E_INIT;
95     }
96 
97     return fwk_interrupt_driver->enable(interrupt);
98 }
99 
fwk_interrupt_disable(unsigned int interrupt)100 int fwk_interrupt_disable(unsigned int interrupt)
101 {
102     if (!initialized) {
103         return FWK_E_INIT;
104     }
105 
106     return fwk_interrupt_driver->disable(interrupt);
107 }
108 
fwk_interrupt_is_pending(unsigned int interrupt,bool * pending)109 int fwk_interrupt_is_pending(unsigned int interrupt, bool *pending)
110 {
111     if (!initialized) {
112         return FWK_E_INIT;
113     }
114 
115     if (pending == NULL) {
116         return FWK_E_PARAM;
117     }
118 
119     return fwk_interrupt_driver->is_pending(interrupt, pending);
120 }
121 
fwk_interrupt_set_pending(unsigned int interrupt)122 int fwk_interrupt_set_pending(unsigned int interrupt)
123 {
124     if (!initialized) {
125         return FWK_E_INIT;
126     }
127 
128     return fwk_interrupt_driver->set_pending(interrupt);
129 }
130 
fwk_interrupt_clear_pending(unsigned int interrupt)131 int fwk_interrupt_clear_pending(unsigned int interrupt)
132 {
133     if (!initialized) {
134         return FWK_E_INIT;
135     }
136 
137     return fwk_interrupt_driver->clear_pending(interrupt);
138 }
139 
fwk_interrupt_set_isr(unsigned int interrupt,void (* isr)(void))140 int fwk_interrupt_set_isr(unsigned int interrupt, void (*isr)(void))
141 {
142     if (!initialized) {
143         return FWK_E_INIT;
144     }
145 
146     if (isr == NULL) {
147         return FWK_E_PARAM;
148     }
149 
150     if (interrupt == FWK_INTERRUPT_NMI) {
151         return fwk_interrupt_driver->set_isr_nmi(isr);
152     } else {
153         return fwk_interrupt_driver->set_isr_irq(interrupt, isr);
154     }
155 }
156 
fwk_interrupt_set_isr_param(unsigned int interrupt,void (* isr)(uintptr_t param),uintptr_t param)157 int fwk_interrupt_set_isr_param(unsigned int interrupt,
158                                 void (*isr)(uintptr_t param),
159                                 uintptr_t param)
160 {
161     if (!initialized) {
162         return FWK_E_INIT;
163     }
164 
165     if (isr == NULL) {
166         return FWK_E_PARAM;
167     }
168 
169     if (interrupt == FWK_INTERRUPT_NMI) {
170         return fwk_interrupt_driver->set_isr_nmi_param(isr, param);
171     } else {
172         return fwk_interrupt_driver->set_isr_irq_param(interrupt, isr, param);
173     }
174 }
175 
fwk_interrupt_get_current(unsigned int * interrupt)176 int fwk_interrupt_get_current(unsigned int *interrupt)
177 {
178     if (!initialized) {
179         return FWK_E_INIT;
180     }
181 
182     if (interrupt == NULL) {
183         return FWK_E_PARAM;
184     }
185 
186     return fwk_interrupt_driver->get_current(interrupt);
187 }
188 
fwk_is_interrupt_context(void)189 bool fwk_is_interrupt_context(void)
190 {
191     if (!initialized) {
192         return false;
193     }
194 
195     return fwk_interrupt_driver->is_interrupt_context();
196 }
197 
198 /* This function is only for internal use by the framework */
fwk_interrupt_set_isr_fault(void (* isr)(void))199 int fwk_interrupt_set_isr_fault(void (*isr)(void))
200 {
201     if (!initialized) {
202         return FWK_E_INIT;
203     }
204 
205     if (isr == NULL) {
206         return FWK_E_PARAM;
207     }
208 
209     return fwk_interrupt_driver->set_isr_fault(isr);
210 }
211