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 * 2018/10/01 Bernard The first version
9 * 2018/12/27 Jesven Change irq enable/disable to cpu0
10 */
11
12 #include <rtthread.h>
13
14 #include "tick.h"
15
16 #include <plic.h>
17 #include <clint.h>
18 #include <interrupt.h>
19
20 #define CPU_NUM 2
21 #define MAX_HANDLERS IRQN_MAX
22
23 static struct rt_irq_desc irq_desc[MAX_HANDLERS];
24
rt_hw_interrupt_handle(rt_uint32_t vector,void * param)25 static rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
26 {
27 rt_kprintf("UN-handled interrupt %d occurred!!!\n", vector);
28 return RT_NULL;
29 }
30
rt_hw_clint_ipi_enable(void)31 int rt_hw_clint_ipi_enable(void)
32 {
33 /* Set the Machine-Software bit in MIE */
34 set_csr(mie, MIP_MSIP);
35 return 0;
36 }
37
rt_hw_clint_ipi_disable(void)38 int rt_hw_clint_ipi_disable(void)
39 {
40 /* Clear the Machine-Software bit in MIE */
41 clear_csr(mie, MIP_MSIP);
42 return 0;
43 }
44
rt_hw_plic_irq_enable(plic_irq_t irq_number)45 int rt_hw_plic_irq_enable(plic_irq_t irq_number)
46 {
47 unsigned long core_id = 0;
48
49 /* Check parameters */
50 if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
51 return -1;
52 /* Get current enable bit array by IRQ number */
53 uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
54 /* Set enable bit in enable bit array */
55 current |= (uint32_t)1 << (irq_number % 32);
56 /* Write back the enable bit array */
57 plic->target_enables.target[core_id].enable[irq_number / 32] = current;
58 return 0;
59 }
60
rt_hw_plic_irq_disable(plic_irq_t irq_number)61 int rt_hw_plic_irq_disable(plic_irq_t irq_number)
62 {
63 unsigned long core_id = 0;
64
65 /* Check parameters */
66 if (PLIC_NUM_SOURCES < irq_number || 0 > irq_number)
67 return -1;
68 /* Get current enable bit array by IRQ number */
69 uint32_t current = plic->target_enables.target[core_id].enable[irq_number / 32];
70 /* Clear enable bit in enable bit array */
71 current &= ~((uint32_t)1 << (irq_number % 32));
72 /* Write back the enable bit array */
73 plic->target_enables.target[core_id].enable[irq_number / 32] = current;
74 return 0;
75 }
76
77 /**
78 * This function will initialize hardware interrupt
79 */
rt_hw_interrupt_init(void)80 void rt_hw_interrupt_init(void)
81 {
82 int idx;
83 int cpuid;
84
85 cpuid = current_coreid();
86
87 /* Disable all interrupts for the current core. */
88 for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++)
89 plic->target_enables.target[cpuid].enable[idx] = 0;
90
91 /* Set priorities to zero. */
92 for (idx = 0; idx < PLIC_NUM_SOURCES; idx++)
93 plic->source_priorities.priority[idx] = 0;
94
95 /* Set the threshold to zero. */
96 plic->targets.target[cpuid].priority_threshold = 0;
97
98 /* init exceptions table */
99 for (idx = 0; idx < MAX_HANDLERS; idx++)
100 {
101 rt_hw_interrupt_mask(idx);
102 irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
103 irq_desc[idx].param = RT_NULL;
104 #ifdef RT_USING_INTERRUPT_INFO
105 rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
106 irq_desc[idx].counter = 0;
107 #endif
108 }
109
110 /* Enable machine external interrupts. */
111 set_csr(mie, MIP_MEIP);
112 }
113
rt_hw_scondary_interrupt_init(void)114 void rt_hw_scondary_interrupt_init(void)
115 {
116 int idx;
117 int cpuid;
118
119 cpuid = current_coreid();
120
121 /* Disable all interrupts for the current core. */
122 for (idx = 0; idx < ((PLIC_NUM_SOURCES + 32u) / 32u); idx ++)
123 plic->target_enables.target[cpuid].enable[idx] = 0;
124
125 /* Set the threshold to zero. */
126 plic->targets.target[cpuid].priority_threshold = 0;
127
128 /* Enable machine external interrupts. */
129 set_csr(mie, MIP_MEIP);
130 }
131
132 /**
133 * This function will mask a interrupt.
134 * @param vector the interrupt number
135 */
rt_hw_interrupt_mask(int vector)136 void rt_hw_interrupt_mask(int vector)
137 {
138 rt_hw_plic_irq_disable(vector);
139 }
140
141 /**
142 * This function will un-mask a interrupt.
143 * @param vector the interrupt number
144 */
rt_hw_interrupt_umask(int vector)145 void rt_hw_interrupt_umask(int vector)
146 {
147 plic_set_priority(vector, 1);
148 rt_hw_plic_irq_enable(vector);
149 }
150
151 /**
152 * This function will install a interrupt service routine to a interrupt.
153 * @param vector the interrupt number
154 * @param new_handler the interrupt service routine to be installed
155 * @param old_handler the old interrupt service routine
156 */
rt_hw_interrupt_install(int vector,rt_isr_handler_t handler,void * param,const char * name)157 rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
158 void *param, const char *name)
159 {
160 rt_isr_handler_t old_handler = RT_NULL;
161
162 if(vector < MAX_HANDLERS)
163 {
164 old_handler = irq_desc[vector].handler;
165 if (handler != RT_NULL)
166 {
167 irq_desc[vector].handler = (rt_isr_handler_t)handler;
168 irq_desc[vector].param = param;
169 #ifdef RT_USING_INTERRUPT_INFO
170 rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
171 irq_desc[vector].counter = 0;
172 #endif
173 }
174 }
175
176 return old_handler;
177 }
178
plic_irq_handle(plic_irq_t irq)179 static void plic_irq_handle(plic_irq_t irq)
180 {
181 plic_instance_t (*plic_instance)[IRQN_MAX] = plic_get_instance();
182 if (plic_instance[0][irq].callback)
183 {
184 plic_instance[0][irq].callback(
185 plic_instance[0][irq].ctx);
186 }
187 else if (plic_instance[1][irq].callback)
188 {
189 plic_instance[1][irq].callback(
190 plic_instance[1][irq].ctx);
191 }
192 }
193
rt_hw_soft_irq_isr(void)194 void rt_hw_soft_irq_isr(void)
195 {
196 uint64_t core_id = current_coreid();
197
198 clint_ipi_clear(core_id);
199 rt_schedule();
200 }
201
rt_hw_irq_isr(void)202 void rt_hw_irq_isr(void)
203 {
204 /*
205 * After the highest-priority pending interrupt is claimed by a target
206 * and the corresponding IP bit is cleared, other lower-priority
207 * pending interrupts might then become visible to the target, and so
208 * the PLIC EIP bit might not be cleared after a claim. The interrupt
209 * handler can check the local meip/heip/seip/ueip bits before exiting
210 * the handler, to allow more efficient service of other interrupts
211 * without first restoring the interrupted context and taking another
212 * interrupt trap.
213 */
214 if (read_csr(mip) & MIP_MEIP)
215 {
216 /* Get current core id */
217 uint64_t core_id = current_coreid();
218 /* Get primitive interrupt enable flag */
219 uint64_t ie_flag = read_csr(mie);
220 /* Get current IRQ num */
221 uint32_t int_num = plic->targets.target[core_id].claim_complete;
222 /* Get primitive IRQ threshold */
223 uint32_t int_threshold = plic->targets.target[core_id].priority_threshold;
224 /* Set new IRQ threshold = current IRQ threshold */
225 plic->targets.target[core_id].priority_threshold = plic->source_priorities.priority[int_num];
226
227 /* Disable software interrupt and timer interrupt */
228 clear_csr(mie, MIP_MTIP | MIP_MSIP);
229
230 if (irq_desc[int_num].handler == (rt_isr_handler_t)rt_hw_interrupt_handle)
231 {
232 /* default handler, route to kendryte bsp plic driver */
233 plic_irq_handle(int_num);
234 }
235 else if (irq_desc[int_num].handler)
236 {
237 irq_desc[int_num].handler(int_num, irq_desc[int_num].param);
238 }
239
240 /* Perform IRQ complete */
241 plic->targets.target[core_id].claim_complete = int_num;
242 /* Set MPIE and MPP flag used to MRET instructions restore MIE flag */
243 set_csr(mstatus, MSTATUS_MPIE | MSTATUS_MPP);
244 /* Restore primitive interrupt enable flag */
245 write_csr(mie, ie_flag);
246 /* Restore primitive IRQ threshold */
247 plic->targets.target[core_id].priority_threshold = int_threshold;
248 }
249 }
250
251