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