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 * 2024/01/11 flyingcys The first version
9 */
10
11 #include <rthw.h>
12 #include <rtthread.h>
13
14 #include "interrupt.h"
15 #include "encoding.h"
16 #include "mmio.h"
17
18 extern rt_atomic_t rt_interrupt_nest;
19 extern rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
20 extern rt_uint32_t rt_thread_switch_interrupt_flag;
21
22 struct rt_irq_desc isr_table[INTERRUPTS_MAX];
23
plic_enable_irq(int irq)24 static void plic_enable_irq(int irq)
25 {
26 uint32_t mask = (irq);
27 uint32_t value = 0;
28
29 if(irq < 16) {
30 rt_kprintf("unmask irq_num is %d\n",irq);
31 return;
32 }
33 value = mmio_read_32(PLIC_ENABLE1 + 4 * (mask / 32));
34 value |= (0x1 << (mask % 32));
35 mmio_write_32((PLIC_ENABLE1 + (mask / 32) * 4), value);
36 }
37
plic_disable_irq(int irq)38 static void plic_disable_irq(int irq)
39 {
40 uint32_t mask = (irq);
41 uint32_t value = 0;
42
43 if(irq < 16) {
44 rt_kprintf("mask irq_num is %d\n", irq);
45 return;
46 }
47 value = mmio_read_32(PLIC_ENABLE1 + 4 * (mask / 32));
48 value &= ~(0x1 << (mask % 32));
49 mmio_write_32((PLIC_ENABLE1 + (mask / 32) * 4), value);
50 }
51
plic_set_priority(int irq,int priority)52 static void plic_set_priority(int irq, int priority)
53 {
54 mmio_write_32((PLIC_PRIORITY0 + irq * 4), priority);
55 }
56
plic_set_threshold(uint32_t threshold)57 static void plic_set_threshold(uint32_t threshold)
58 {
59 mmio_write_32((PLIC_THRESHOLD), threshold);
60 }
61
plic_init(void)62 void plic_init(void)
63 {
64 int i;
65
66 for (i = 0; i < IRQ_MAX_NR * 4; i = i + 4)
67 {
68 mmio_write_32(((uintptr_t) PLIC_PRIORITY0 + i), 0);
69 }
70
71 for ( i = 0; i < IRQ_MAX_NR / 32; i ++)
72 {
73 mmio_write_32((PLIC_PENDING1 + i * 4), 0);
74 mmio_write_32((PLIC_ENABLE1 + i * 4), 0);
75 }
76 plic_set_threshold(0);
77
78 /* Enable machine external interrupts. */
79 set_csr(mie, MIP_MEIP);
80 }
81
rt_hw_interrupt_handler(int vector,void * param)82 static void rt_hw_interrupt_handler(int vector, void *param)
83 {
84 rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
85 }
86
87 /**
88 * This function will initialize hardware interrupt
89 */
rt_hw_interrupt_init(void)90 void rt_hw_interrupt_init(void)
91 {
92 /* init interrupt controller */
93 plic_init();
94
95 rt_int32_t idx;
96
97 rt_memset(isr_table, 0x00, sizeof(isr_table));
98 for (idx = 0; idx < INTERRUPTS_MAX; idx++)
99 {
100 isr_table[idx].handler = rt_hw_interrupt_handler;
101 }
102
103 /* init interrupt nest, and context in thread sp */
104 rt_interrupt_nest = 0;
105 rt_interrupt_from_thread = 0;
106 rt_interrupt_to_thread = 0;
107 rt_thread_switch_interrupt_flag = 0;
108 }
109
110 /**
111 * This function will mask a interrupt.
112 * @param vector the interrupt number
113 */
rt_hw_interrupt_mask(int vector)114 void rt_hw_interrupt_mask(int vector)
115 {
116 if ((vector < 0) || (vector > IRQ_MAX_NR))
117 {
118 return;
119 }
120 plic_disable_irq(vector);
121 }
122
123 /**
124
125 * This function will un-mask a interrupt.
126 * @param vector the interrupt number
127 */
rt_hw_interrupt_umask(int vector)128 void rt_hw_interrupt_umask(int vector)
129 {
130 if ((vector < 0) || (vector > IRQ_MAX_NR))
131 {
132 return;
133 }
134
135 plic_enable_irq(vector);
136 }
137
138 /**
139 * This function will install a interrupt service routine to a interrupt.
140 * @param vector the interrupt number
141 * @param handler the interrupt service routine to be installed
142 * @param param the interrupt service function parameter
143 * @param name the interrupt name
144 * @return old handler
145 */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)146 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
147 void *param, const char *name)
148 {
149 rt_isr_handler_t old_handler = RT_NULL;
150 if ((vector < 0) || (vector > IRQ_MAX_NR))
151 {
152 return old_handler;
153 }
154
155 old_handler = isr_table[vector].handler;
156
157 #ifdef RT_USING_INTERRUPT_INFO
158 rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX);
159 #endif /* RT_USING_INTERRUPT_INFO */
160 isr_table[vector].handler = handler;
161 isr_table[vector].param = param;
162
163 // set highest priority
164 plic_set_priority(vector, 7);
165
166 return old_handler;
167 }
168
rt_hw_irq_isr(void)169 void rt_hw_irq_isr(void)
170 {
171 int irq = mmio_read_32(PLIC_CLAIM);
172 rt_isr_handler_t isr;
173 void *param;
174
175 if (irq < 0 || irq >= IRQ_MAX_NR)
176 {
177 rt_kprintf("bad irq number %d!\n", irq);
178 return;
179 }
180
181 if (!irq) // irq = 0 => no irq
182 {
183 rt_kprintf("no irq!\n");
184 return;
185 }
186 isr = isr_table[irq].handler;
187 param = isr_table[irq].param;
188 if (isr != RT_NULL)
189 {
190 isr(irq, param);
191 }
192
193 mmio_write_32(PLIC_CLAIM, irq);
194
195 // clear external interrupt pending
196 clear_csr(mip, MIP_MEIP);
197 }
198