1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9
10 #include <rthw.h>
11 #include <plic_driver.h>
12 #include <platform.h>
13 #include <encoding.h>
14 #include <interrupt.h>
15
16 #define MAX_HANDLERS PLIC_NUM_INTERRUPTS
17
18 /* exception and interrupt handler table */
19 static struct rt_irq_desc irq_desc[MAX_HANDLERS];
20
21 static plic_instance_t g_plic;
22
23 /**
24 * This function will mask a interrupt.
25 * @param vector the interrupt number
26 */
rt_hw_interrupt_mask(int irq)27 void rt_hw_interrupt_mask(int irq)
28 {
29 PLIC_disable_interrupt(&g_plic, irq);
30 }
31
32 /**
33 * This function will un-mask a interrupt.
34 * @param vector the interrupt number
35 */
rt_hw_interrupt_unmask(int irq)36 void rt_hw_interrupt_unmask(int irq)
37 {
38 PLIC_enable_interrupt(&g_plic, irq);
39 PLIC_set_priority(&g_plic, irq, 1);
40 }
41
rt_hw_interrupt_handle(rt_uint32_t vector,void * param)42 rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
43 {
44 rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
45 return RT_NULL;
46 }
47
rt_hw_interrupt_init(void)48 void rt_hw_interrupt_init(void)
49 {
50 int idx;
51
52 /* config interrupt vector*/
53 asm volatile(
54 "la t0, SW_handler\n"
55 "csrw mtvec, t0"
56 );
57
58 /* enable global interrupt*/
59 PLIC_init(&g_plic,
60 PLIC_CTRL_ADDR,
61 PLIC_NUM_INTERRUPTS,
62 PLIC_NUM_PRIORITIES);
63
64 /* init exceptions table */
65 for (idx = 0; idx < MAX_HANDLERS; idx++)
66 {
67 rt_hw_interrupt_mask(idx);
68 irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
69 irq_desc[idx].param = RT_NULL;
70 #ifdef RT_USING_INTERRUPT_INFO
71 rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
72 irq_desc[idx].counter = 0;
73 #endif
74 }
75
76 // enable machine external interrupt
77 set_csr(mie, MIP_MEIP);
78 }
79
rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)80 rt_uint32_t rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)
81 {
82 return (rt_uint32_t)PLIC_claim_interrupt(&g_plic);
83 }
84
rt_hw_interrupt_ack(rt_uint32_t fiq_irq,rt_uint32_t id)85 void rt_hw_interrupt_ack(rt_uint32_t fiq_irq, rt_uint32_t id)
86 {
87 PLIC_complete_interrupt(&g_plic, id);
88 }
89
90 /**
91 * This function will install a interrupt service routine to a interrupt.
92 * @param vector the interrupt number
93 * @param handler the interrupt service routine to be installed
94 * @param param the interrupt service function parameter
95 * @param name the interrupt name
96 * @return old handler
97 */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)98 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
99 void *param, const char *name)
100 {
101 rt_isr_handler_t old_handler = RT_NULL;
102
103 if(vector < MAX_HANDLERS)
104 {
105 old_handler = irq_desc[vector].handler;
106 if (handler != RT_NULL)
107 {
108 irq_desc[vector].handler = (rt_isr_handler_t)handler;
109 irq_desc[vector].param = param;
110 #ifdef RT_USING_INTERRUPT_INFO
111 rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
112 irq_desc[vector].counter = 0;
113 #endif
114 }
115 }
116
117 return old_handler;
118 }
119
120 /**
121 * This function will be call when external machine-level
122 * interrupt from PLIC occurred.
123 */
handle_m_ext_interrupt(void)124 void handle_m_ext_interrupt(void)
125 {
126 rt_isr_handler_t isr_func;
127 rt_uint32_t irq;
128 void *param;
129
130 /* get irq number */
131 irq = rt_hw_interrupt_get_active(0);
132
133 /* get interrupt service routine */
134 isr_func = irq_desc[irq].handler;
135 param = irq_desc[irq].param;
136
137 /* turn to interrupt service routine */
138 isr_func(irq, param);
139 rt_hw_interrupt_ack(0, irq);
140
141 #ifdef RT_USING_INTERRUPT_INFO
142 irq_desc[irq].counter ++;
143 #endif
144 }
145