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