1 /*
2 * File : interrupt.c
3 * This file is part of RT-Thread RTOS
4 * COPYRIGHT (C) 2018, RT-Thread Development Team
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Change Logs:
21 * Date Author Notes
22 */
23
24 #include <rthw.h>
25 #include <plic_driver.h>
26 #include <platform.h>
27 #include <encoding.h>
28 #include <interrupt.h>
29
30 #define MAX_HANDLERS PLIC_NUM_INTERRUPTS
31
32 /* exception and interrupt handler table */
33 static struct rt_irq_desc irq_desc[MAX_HANDLERS];
34
35 static plic_instance_t g_plic;
36
37 /**
38 * This function will mask a interrupt.
39 * @param vector the interrupt number
40 */
rt_hw_interrupt_mask(int irq)41 void rt_hw_interrupt_mask(int irq)
42 {
43 PLIC_disable_interrupt(&g_plic, irq);
44 }
45
46 /**
47 * This function will un-mask a interrupt.
48 * @param vector the interrupt number
49 */
rt_hw_interrupt_unmask(int irq)50 void rt_hw_interrupt_unmask(int irq)
51 {
52 PLIC_enable_interrupt(&g_plic, irq);
53 PLIC_set_priority(&g_plic, irq, 1);
54 }
55
rt_hw_interrupt_handle(rt_uint32_t vector,void * param)56 rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
57 {
58 rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
59 return RT_NULL;
60 }
61
rt_hw_interrupt_init(void)62 void rt_hw_interrupt_init(void)
63 {
64 int idx;
65
66 /* config interrupt vector*/
67 asm volatile(
68 "la t0, SW_handler\n"
69 "csrw mtvec, t0"
70 );
71
72 /* enable global interrupt*/
73 PLIC_init(&g_plic,
74 PLIC_CTRL_ADDR,
75 PLIC_NUM_INTERRUPTS,
76 PLIC_NUM_PRIORITIES);
77
78 /* init exceptions table */
79 for (idx = 0; idx < MAX_HANDLERS; idx++)
80 {
81 rt_hw_interrupt_mask(idx);
82 irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
83 irq_desc[idx].param = RT_NULL;
84 #ifdef RT_USING_INTERRUPT_INFO
85 rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
86 irq_desc[idx].counter = 0;
87 #endif
88 }
89
90 // enable machine external interrupt
91 set_csr(mie, MIP_MEIP);
92 }
93
rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)94 rt_uint32_t rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)
95 {
96 return (rt_uint32_t)PLIC_claim_interrupt(&g_plic);;
97 }
98
rt_hw_interrupt_ack(rt_uint32_t fiq_irq,rt_uint32_t id)99 void rt_hw_interrupt_ack(rt_uint32_t fiq_irq, rt_uint32_t id)
100 {
101 PLIC_complete_interrupt(&g_plic, id);
102 }
103
104 /**
105 * This function will install a interrupt service routine to a interrupt.
106 * @param vector the interrupt number
107 * @param handler the interrupt service routine to be installed
108 * @param param the interrupt service function parameter
109 * @param name the interrupt name
110 * @return old handler
111 */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)112 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
113 void *param, const char *name)
114 {
115 rt_isr_handler_t old_handler = RT_NULL;
116
117 if(vector < MAX_HANDLERS)
118 {
119 old_handler = irq_desc[vector].handler;
120 if (handler != RT_NULL)
121 {
122 irq_desc[vector].handler = (rt_isr_handler_t)handler;
123 irq_desc[vector].param = param;
124 #ifdef RT_USING_INTERRUPT_INFO
125 rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
126 irq_desc[vector].counter = 0;
127 #endif
128 }
129 }
130
131 return old_handler;
132 }
133
134 /**
135 * This function will be call when external machine-level
136 * interrupt from PLIC occurred.
137 */
handle_m_ext_interrupt(void)138 void handle_m_ext_interrupt(void)
139 {
140 rt_isr_handler_t isr_func;
141 rt_uint32_t irq;
142 void *param;
143
144 /* get irq number */
145 irq = rt_hw_interrupt_get_active(0);
146
147 /* get interrupt service routine */
148 isr_func = irq_desc[irq].handler;
149 param = irq_desc[irq].param;
150
151 /* turn to interrupt service routine */
152 isr_func(irq, param);
153 rt_hw_interrupt_ack(0, irq);
154
155 #ifdef RT_USING_INTERRUPT_INFO
156 irq_desc[irq].counter ++;
157 #endif
158 }
159