1 /*
2  * Copyright (c) 2006-2024, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2013-07-06     Bernard      first version
9  * 2018-11-22     Jesven       add smp support
10  */
11 
12 #include <rthw.h>
13 #include <rtthread.h>
14 #include "interrupt.h"
15 
16 #include "gicv3.h"
17 
18 /* exception and interrupt handler table */
19 struct rt_irq_desc isr_table[MAX_HANDLERS];
20 
21 #ifndef RT_USING_SMP
22 /* Those varibles will be accessed in ISR, so we need to share them. */
23 rt_uint32_t rt_interrupt_from_thread        = 0;
24 rt_uint32_t rt_interrupt_to_thread          = 0;
25 rt_uint32_t rt_thread_switch_interrupt_flag = 0;
26 
27 #ifdef RT_USING_HOOK
28 static void (*rt_interrupt_switch_hook)(void);
29 
rt_interrupt_switch_sethook(void (* hook)(void))30 void rt_interrupt_switch_sethook(void (*hook)(void))
31 {
32     rt_interrupt_switch_hook = hook;
33 }
34 #endif
35 
rt_interrupt_hook(void)36 void rt_interrupt_hook(void)
37 {
38     RT_OBJECT_HOOK_CALL(rt_interrupt_switch_hook, ());
39 }
40 #endif
41 
42 const unsigned int VECTOR_BASE = 0x00;
43 extern void rt_cpu_vector_set_base(unsigned int addr);
44 extern int system_vectors;
45 
rt_hw_vector_init(void)46 void rt_hw_vector_init(void)
47 {
48     rt_cpu_vector_set_base((unsigned int)&system_vectors);
49 }
50 
51 /**
52  * This function will initialize hardware interrupt
53  * Called by the primary cpu(cpu0)
54  */
rt_hw_interrupt_init(void)55 void rt_hw_interrupt_init(void)
56 {
57     rt_uint32_t gic_dist_base;
58     rt_uint32_t gic_irq_start;
59 
60     /* initialize vector table */
61     /* rt_hw_vector_init(); */
62 
63     /* initialize exceptions table */
64     rt_memset(isr_table, 0x00, sizeof(isr_table));
65 
66     /* initialize ARM GIC */
67     gic_dist_base = platform_get_gic_dist_base();
68     gic_irq_start = GIC_IRQ_START;
69 
70     arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
71 
72     arm_gic_cpu_init(0);
73     arm_gic_redist_init(0);
74 }
75 
76 /**
77  * This function will mask a interrupt.
78  * @param vector the interrupt number
79  */
rt_hw_interrupt_mask(int vector)80 void rt_hw_interrupt_mask(int vector)
81 {
82     arm_gic_mask(0, vector);
83 }
84 
85 /**
86  * This function will un-mask a interrupt.
87  * @param vector the interrupt number
88  */
rt_hw_interrupt_umask(int vector)89 void rt_hw_interrupt_umask(int vector)
90 {
91     arm_gic_umask(0, vector);
92 }
93 
94 /**
95  * This function returns the active interrupt number.
96  * @param none
97  */
rt_hw_interrupt_get_irq(void)98 int rt_hw_interrupt_get_irq(void)
99 {
100     return arm_gic_get_active_irq(0);
101 }
102 
103 /**
104  * This function acknowledges the interrupt.
105  * @param vector the interrupt number
106  */
rt_hw_interrupt_ack(int vector)107 void rt_hw_interrupt_ack(int vector)
108 {
109     arm_gic_ack(0, vector);
110 }
111 
112 /**
113  * This function set interrupt CPU targets.
114  * @param vector:   the interrupt number
115  *        cpu_mask: target cpus mask, one bit for one core
116  */
rt_hw_interrupt_set_target_cpus(int vector,unsigned int cpu_mask)117 void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask)
118 {
119     arm_gic_set_cpu(0, vector, cpu_mask);
120 }
121 
122 /**
123  * This function get interrupt CPU targets.
124  * @param vector: the interrupt number
125  * @return target cpus mask, one bit for one core
126  */
rt_hw_interrupt_get_target_cpus(int vector)127 unsigned int rt_hw_interrupt_get_target_cpus(int vector)
128 {
129     return arm_gic_get_target_cpu(0, vector);
130 }
131 
132 /**
133  * This function set interrupt triger mode.
134  * @param vector: the interrupt number
135  *        mode:   interrupt triger mode; 0: level triger, 1: edge triger
136  */
rt_hw_interrupt_set_triger_mode(int vector,unsigned int mode)137 void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode)
138 {
139     arm_gic_set_configuration(0, vector, mode);
140 }
141 
142 /**
143  * This function get interrupt triger mode.
144  * @param vector: the interrupt number
145  * @return interrupt triger mode; 0: level triger, 1: edge triger
146  */
rt_hw_interrupt_get_triger_mode(int vector)147 unsigned int rt_hw_interrupt_get_triger_mode(int vector)
148 {
149     return arm_gic_get_configuration(0, vector);
150 }
151 
152 /**
153  * This function set interrupt pending flag.
154  * @param vector: the interrupt number
155  */
rt_hw_interrupt_set_pending(int vector)156 void rt_hw_interrupt_set_pending(int vector)
157 {
158     arm_gic_set_pending_irq(0, vector);
159 }
160 
161 /**
162  * This function get interrupt pending flag.
163  * @param vector: the interrupt number
164  * @return interrupt pending flag, 0: not pending; 1: pending
165  */
rt_hw_interrupt_get_pending(int vector)166 unsigned int rt_hw_interrupt_get_pending(int vector)
167 {
168     return arm_gic_get_pending_irq(0, vector);
169 }
170 
171 /**
172  * This function clear interrupt pending flag.
173  * @param vector: the interrupt number
174  */
rt_hw_interrupt_clear_pending(int vector)175 void rt_hw_interrupt_clear_pending(int vector)
176 {
177     arm_gic_clear_pending_irq(0, vector);
178 }
179 
180 /**
181  * This function set interrupt priority value.
182  * @param vector: the interrupt number
183  *        priority: the priority of interrupt to set
184  */
rt_hw_interrupt_set_priority(int vector,unsigned int priority)185 void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
186 {
187     arm_gic_set_priority(0, vector, priority);
188 }
189 
190 /**
191  * This function get interrupt priority.
192  * @param vector: the interrupt number
193  * @return interrupt priority value
194  */
rt_hw_interrupt_get_priority(int vector)195 unsigned int rt_hw_interrupt_get_priority(int vector)
196 {
197     return arm_gic_get_priority(0, vector);
198 }
199 
200 /**
201  * This function set priority masking threshold.
202  * @param priority: priority masking threshold
203  */
rt_hw_interrupt_set_priority_mask(unsigned int priority)204 void rt_hw_interrupt_set_priority_mask(unsigned int priority)
205 {
206     arm_gic_set_interface_prior_mask(0, priority);
207 }
208 
209 /**
210  * This function get priority masking threshold.
211  * @param none
212  * @return priority masking threshold
213  */
rt_hw_interrupt_get_priority_mask(void)214 unsigned int rt_hw_interrupt_get_priority_mask(void)
215 {
216     return arm_gic_get_interface_prior_mask(0);
217 }
218 
219 /**
220  * This function set priority grouping field split point.
221  * @param bits: priority grouping field split point
222  * @return 0: success; -1: failed
223  */
rt_hw_interrupt_set_prior_group_bits(unsigned int bits)224 int rt_hw_interrupt_set_prior_group_bits(unsigned int bits)
225 {
226     int status;
227 
228     if (bits < 8)
229     {
230         arm_gic_set_binary_point(0, (7 - bits));
231         status = 0;
232     }
233     else
234     {
235         status = -1;
236     }
237 
238     return (status);
239 }
240 
241 /**
242  * This function get priority grouping field split point.
243  * @param none
244  * @return priority grouping field split point
245  */
rt_hw_interrupt_get_prior_group_bits(void)246 unsigned int rt_hw_interrupt_get_prior_group_bits(void)
247 {
248     unsigned int bp;
249 
250     bp = arm_gic_get_binary_point(0) & 0x07;
251 
252     return (7 - bp);
253 }
254 
255 /**
256  * This function will install a interrupt service routine to a interrupt.
257  * @param vector the interrupt number
258  * @param new_handler the interrupt service routine to be installed
259  * @param old_handler the old interrupt service routine
260  */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)261 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
262                                          void *param, const char *name)
263 {
264     rt_isr_handler_t old_handler = RT_NULL;
265 
266     if (vector < MAX_HANDLERS)
267     {
268         old_handler = isr_table[vector].handler;
269 
270         if (handler != RT_NULL)
271         {
272 #ifdef RT_USING_INTERRUPT_INFO
273             rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
274 #endif /* RT_USING_INTERRUPT_INFO */
275             isr_table[vector].handler = handler;
276             isr_table[vector].param = param;
277         }
278     }
279 
280     return old_handler;
281 }
282 
283