1 /*
2  * Copyright (c) 2006-2022, 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 #include "gic.h"
16 #include "gicv3.h"
17 #include "ioremap.h"
18 
19 /* exception and interrupt handler table */
20 struct rt_irq_desc isr_table[MAX_HANDLERS];
21 
22 #ifndef RT_CPUS_NR
23 #define RT_CPUS_NR 1
24 #endif
25 
26 const unsigned int VECTOR_BASE = 0x00;
27 extern void rt_cpu_vector_set_base(void *addr);
28 extern void *system_vectors;
29 
30 #ifdef RT_USING_SMP
31 #define rt_interrupt_nest rt_cpu_self()->irq_nest
32 #else
33 extern volatile rt_atomic_t rt_interrupt_nest;
34 #endif
35 
36 #ifdef SOC_BCM283x
default_isr_handler(int vector,void * param)37 static void default_isr_handler(int vector, void *param)
38 {
39 #ifdef RT_USING_SMP
40     rt_kprintf("cpu %d unhandled irq: %d\n", rt_hw_cpu_id(),vector);
41 #else
42     rt_kprintf("unhandled irq: %d\n",vector);
43 #endif
44 }
45 #endif
46 
rt_hw_vector_init(void)47 void rt_hw_vector_init(void)
48 {
49     rt_cpu_vector_set_base(&system_vectors);
50 }
51 
52 /**
53  * This function will initialize hardware interrupt
54  */
rt_hw_interrupt_init(void)55 void rt_hw_interrupt_init(void)
56 {
57 #ifdef SOC_BCM283x
58     rt_uint32_t index;
59     /* initialize vector table */
60     rt_hw_vector_init();
61 
62     /* initialize exceptions table */
63     rt_memset(isr_table, 0x00, sizeof(isr_table));
64 
65     /* mask all of interrupts */
66     IRQ_DISABLE_BASIC = 0x000000ff;
67     IRQ_DISABLE1      = 0xffffffff;
68     IRQ_DISABLE2      = 0xffffffff;
69     for (index = 0; index < MAX_HANDLERS; index ++)
70     {
71         isr_table[index].handler = default_isr_handler;
72         isr_table[index].param = RT_NULL;
73 #ifdef RT_USING_INTERRUPT_INFO
74         rt_strncpy(isr_table[index].name, "unknown", RT_NAME_MAX);
75         isr_table[index].counter = 0;
76 #endif
77     }
78 
79     /* init interrupt nest, and context in thread sp */
80     rt_atomic_store(&rt_interrupt_nest, 0);
81 #else
82     rt_uint64_t gic_cpu_base;
83     rt_uint64_t gic_dist_base;
84 #ifdef BSP_USING_GICV3
85     rt_uint64_t gic_rdist_base;
86 #endif
87     rt_uint64_t gic_irq_start;
88 
89     /* initialize vector table */
90     rt_hw_vector_init();
91 
92     /* initialize exceptions table */
93     rt_memset(isr_table, 0x00, sizeof(isr_table));
94 
95     /* initialize ARM GIC */
96 #if defined(RT_USING_SMART) || defined(RT_USING_OFW)
97     gic_dist_base = (rt_uint64_t)rt_ioremap((void*)platform_get_gic_dist_base(), 0x40000);
98     gic_cpu_base = (rt_uint64_t)rt_ioremap((void*)platform_get_gic_cpu_base(), 0x1000);
99 #ifdef BSP_USING_GICV3
100     gic_rdist_base = (rt_uint64_t)rt_ioremap((void*)platform_get_gic_redist_base(),
101             ARM_GIC_CPU_NUM * (2 << 16));
102 #endif
103 #else
104     gic_dist_base = platform_get_gic_dist_base();
105     gic_cpu_base = platform_get_gic_cpu_base();
106 #ifdef BSP_USING_GICV3
107     gic_rdist_base = platform_get_gic_redist_base();
108 #endif
109 #endif
110 
111     gic_irq_start = GIC_IRQ_START;
112 
113     arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
114     arm_gic_cpu_init(0, gic_cpu_base);
115 #ifdef BSP_USING_GICV3
116     arm_gic_redist_init(0, gic_rdist_base);
117 #endif
118 #endif
119 }
120 
121 /**
122  * This function will mask a interrupt.
123  * @param vector the interrupt number
124  */
rt_hw_interrupt_mask(int vector)125 void rt_hw_interrupt_mask(int vector)
126 {
127 #ifdef SOC_BCM283x
128     if (vector < 32)
129     {
130         IRQ_DISABLE1 = (1UL << vector);
131     }
132     else if (vector < 64)
133     {
134         vector = vector % 32;
135         IRQ_DISABLE2 = (1UL << vector);
136     }
137     else
138     {
139         vector = vector - 64;
140         IRQ_DISABLE_BASIC = (1UL << vector);
141     }
142 #else
143     arm_gic_mask(0, vector);
144 #endif
145 }
146 
147 /**
148  * This function will un-mask a interrupt.
149  * @param vector the interrupt number
150  */
rt_hw_interrupt_umask(int vector)151 void rt_hw_interrupt_umask(int vector)
152 {
153 #ifdef SOC_BCM283x
154 if (vector < 32)
155     {
156         IRQ_ENABLE1 = (1UL << vector);
157     }
158     else if (vector < 64)
159     {
160         vector = vector % 32;
161         IRQ_ENABLE2 = (1UL << vector);
162     }
163     else
164     {
165         vector = vector - 64;
166         IRQ_ENABLE_BASIC = (1UL << vector);
167     }
168 #else
169     arm_gic_umask(0, vector);
170 #endif
171 }
172 
173 /**
174  * This function returns the active interrupt number.
175  * @param none
176  */
rt_hw_interrupt_get_irq(void)177 int rt_hw_interrupt_get_irq(void)
178 {
179 #ifndef SOC_BCM283x
180     return arm_gic_get_active_irq(0);
181 #else
182     return 0;
183 #endif
184 }
185 
186 /**
187  * This function acknowledges the interrupt.
188  * @param vector the interrupt number
189  */
rt_hw_interrupt_ack(int vector)190 void rt_hw_interrupt_ack(int vector)
191 {
192 #ifndef SOC_BCM283x
193     arm_gic_ack(0, vector);
194 #endif
195 }
196 
197 #ifndef SOC_BCM283x
198 /**
199  * This function set interrupt CPU targets.
200  * @param vector:   the interrupt number
201  *        cpu_mask: target cpus mask, one bit for one core
202  */
rt_hw_interrupt_set_target_cpus(int vector,unsigned long cpu_mask)203 void rt_hw_interrupt_set_target_cpus(int vector, unsigned long cpu_mask)
204 {
205 #ifdef BSP_USING_GIC
206 #ifdef BSP_USING_GICV3
207     arm_gic_set_router_cpu(0, vector, cpu_mask);
208 #else
209     arm_gic_set_cpu(0, vector, (unsigned int) cpu_mask);
210 #endif
211 #endif
212 }
213 
214 /**
215  * This function get interrupt CPU targets.
216  * @param vector: the interrupt number
217  * @return target cpus mask, one bit for one core
218  */
rt_hw_interrupt_get_target_cpus(int vector)219 unsigned int rt_hw_interrupt_get_target_cpus(int vector)
220 {
221     return arm_gic_get_target_cpu(0, vector);
222 }
223 
224 /**
225  * This function set interrupt triger mode.
226  * @param vector: the interrupt number
227  *        mode:   interrupt triger mode; 0: level triger, 1: edge triger
228  */
rt_hw_interrupt_set_triger_mode(int vector,unsigned int mode)229 void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode)
230 {
231     arm_gic_set_configuration(0, vector, mode & IRQ_MODE_MASK);
232 }
233 
234 /**
235  * This function get interrupt triger mode.
236  * @param vector: the interrupt number
237  * @return interrupt triger mode; 0: level triger, 1: edge triger
238  */
rt_hw_interrupt_get_triger_mode(int vector)239 unsigned int rt_hw_interrupt_get_triger_mode(int vector)
240 {
241     return arm_gic_get_configuration(0, vector);
242 }
243 
244 /**
245  * This function set interrupt pending flag.
246  * @param vector: the interrupt number
247  */
rt_hw_interrupt_set_pending(int vector)248 void rt_hw_interrupt_set_pending(int vector)
249 {
250     arm_gic_set_pending_irq(0, vector);
251 }
252 
253 /**
254  * This function get interrupt pending flag.
255  * @param vector: the interrupt number
256  * @return interrupt pending flag, 0: not pending; 1: pending
257  */
rt_hw_interrupt_get_pending(int vector)258 unsigned int rt_hw_interrupt_get_pending(int vector)
259 {
260     return arm_gic_get_pending_irq(0, vector);
261 }
262 
263 /**
264  * This function clear interrupt pending flag.
265  * @param vector: the interrupt number
266  */
rt_hw_interrupt_clear_pending(int vector)267 void rt_hw_interrupt_clear_pending(int vector)
268 {
269     arm_gic_clear_pending_irq(0, vector);
270 }
271 
272 /**
273  * This function set interrupt priority value.
274  * @param vector: the interrupt number
275  *        priority: the priority of interrupt to set
276  */
rt_hw_interrupt_set_priority(int vector,unsigned int priority)277 void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
278 {
279     arm_gic_set_priority(0, vector, priority);
280 }
281 
282 /**
283  * This function get interrupt priority.
284  * @param vector: the interrupt number
285  * @return interrupt priority value
286  */
rt_hw_interrupt_get_priority(int vector)287 unsigned int rt_hw_interrupt_get_priority(int vector)
288 {
289     return arm_gic_get_priority(0, vector);
290 }
291 
292 /**
293  * This function set priority masking threshold.
294  * @param priority: priority masking threshold
295  */
rt_hw_interrupt_set_priority_mask(unsigned int priority)296 void rt_hw_interrupt_set_priority_mask(unsigned int priority)
297 {
298     arm_gic_set_interface_prior_mask(0, priority);
299 }
300 
301 /**
302  * This function get priority masking threshold.
303  * @param none
304  * @return priority masking threshold
305  */
rt_hw_interrupt_get_priority_mask(void)306 unsigned int rt_hw_interrupt_get_priority_mask(void)
307 {
308     return arm_gic_get_interface_prior_mask(0);
309 }
310 
311 /**
312  * This function set priority grouping field split point.
313  * @param bits: priority grouping field split point
314  * @return 0: success; -1: failed
315  */
rt_hw_interrupt_set_prior_group_bits(unsigned int bits)316 int rt_hw_interrupt_set_prior_group_bits(unsigned int bits)
317 {
318     int status;
319 
320     if (bits < 8)
321     {
322         arm_gic_set_binary_point(0, (7 - bits));
323         status = 0;
324     }
325     else
326     {
327         status = -1;
328     }
329 
330     return (status);
331 }
332 
333 /**
334  * This function get priority grouping field split point.
335  * @param none
336  * @return priority grouping field split point
337  */
rt_hw_interrupt_get_prior_group_bits(void)338 unsigned int rt_hw_interrupt_get_prior_group_bits(void)
339 {
340     unsigned int bp;
341 
342     bp = arm_gic_get_binary_point(0) & 0x07;
343 
344     return (7 - bp);
345 }
346 #endif /* SOC_BCM283x */
347 
348 /**
349  * This function will install a interrupt service routine to a interrupt.
350  * @param vector the interrupt number
351  * @param new_handler the interrupt service routine to be installed
352  * @param old_handler the old interrupt service routine
353  */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)354 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
355         void *param, const char *name)
356 {
357     rt_isr_handler_t old_handler = RT_NULL;
358 
359     if (vector < MAX_HANDLERS)
360     {
361         old_handler = isr_table[vector].handler;
362 
363         if (handler != RT_NULL)
364         {
365 #ifdef RT_USING_INTERRUPT_INFO
366             rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
367 #endif /* RT_USING_INTERRUPT_INFO */
368             isr_table[vector].handler = handler;
369             isr_table[vector].param = param;
370         }
371     }
372 
373 #ifdef BSP_USING_GIC
374     if (vector > 32)
375     {
376 #ifdef BSP_USING_GICV3
377         rt_uint64_t cpu_affinity_val;
378         __asm__ volatile ("mrs %0, mpidr_el1":"=r"(cpu_affinity_val));
379         rt_hw_interrupt_set_target_cpus(vector, cpu_affinity_val);
380 #else
381         rt_hw_interrupt_set_target_cpus(vector, 1 << rt_hw_cpu_id());
382 #endif /* BSP_USING_GICV3 */
383     }
384 #endif
385 
386     return old_handler;
387 }
388 
389 #if defined(RT_USING_SMP) || defined(RT_USING_AMP)
rt_hw_ipi_send(int ipi_vector,unsigned int cpu_mask)390 void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
391 {
392 #ifdef BSP_USING_GICV2
393     arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0);
394 #elif defined(BSP_USING_GICV3)
395     rt_uint32_t gicv3_cpu_mask[(RT_CPUS_NR + 31) >> 5];
396     gicv3_cpu_mask[0] = cpu_mask;
397     arm_gic_send_affinity_sgi(0, ipi_vector, gicv3_cpu_mask, GICV3_ROUTED_TO_SPEC);
398 #endif
399 }
400 
rt_hw_ipi_handler_install(int ipi_vector,rt_isr_handler_t ipi_isr_handler)401 void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
402 {
403     /* note: ipi_vector maybe different with irq_vector */
404     rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER");
405 }
406 #endif
407 
408 #if defined(FINSH_USING_MSH) && defined(RT_USING_INTERRUPT_INFO)
list_isr()409 int list_isr()
410 {
411     int idx;
412 
413     rt_kprintf("%-*.*s nr   handler            param              counter         ", RT_NAME_MAX, RT_NAME_MAX, "irq");
414 #ifdef RT_USING_SMP
415     for (int i = 0; i < RT_CPUS_NR; i++)
416     {
417         rt_kprintf(" cpu%2d  ", i);
418     }
419 #endif
420     rt_kprintf("\n");
421     for (int i = 0; i < RT_NAME_MAX; i++)
422     {
423         rt_kprintf("-");
424     }
425     rt_kprintf(" ---- ------------------ ------------------ ----------------");
426 #ifdef RT_USING_SMP
427     for (int i = 0; i < RT_CPUS_NR; i++)
428     {
429         rt_kprintf(" -------");
430     }
431 #endif
432     rt_kprintf("\n");
433     for (idx = 0; idx < MAX_HANDLERS; idx++)
434     {
435         if (isr_table[idx].handler != RT_NULL)
436         {
437             rt_kprintf("%*.s %4d %p %p %16d", RT_NAME_MAX, isr_table[idx].name, idx, isr_table[idx].handler,
438                        isr_table[idx].param, isr_table[idx].counter);
439 #ifdef RT_USING_SMP
440             for (int i = 0; i < RT_CPUS_NR; i++)
441                  rt_kprintf(" %7d", isr_table[idx].cpu_counter[i]);
442 #endif
443             rt_kprintf("\n");
444         }
445     }
446     return 0;
447 }
448 
449 #include "finsh.h"
450 MSH_CMD_EXPORT(list_isr, list isr)
451 #endif
452