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