1 /*
2 * Copyright (c) 2019 Western Digital Corporation or its affiliates
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT swerv_pic
8
9 /**
10 * @brief SweRV EH1 PIC driver
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/arch/cpu.h>
15 #include <zephyr/device.h>
16 #include <zephyr/sw_isr_table.h>
17 #include <zephyr/irq.h>
18 #include <zephyr/arch/riscv/irq.h>
19
20 #define SWERV_PIC_MAX_NUM CONFIG_NUM_IRQS
21 #define SWERV_PIC_MAX_ID (SWERV_PIC_MAX_NUM + RISCV_MAX_GENERIC_IRQ)
22 #define SWERV_PIC_MAX_PRIO 16
23
24 #define SWERV_PIC_mpiccfg 0x3000
25 #define SWERV_PIC_meipl(s) (0x0 + (s)*4)
26 #define SWERV_PIC_meip(x) (0x1000 + (x)*4)
27 #define SWERV_PIC_meie(s) (0x2000 + (s)*4)
28 #define SWERV_PIC_meigwctrl(s) (0x4000 + (s)*4)
29 #define SWERV_PIC_meigwclr(s) (0x5000 + (s)*4)
30
31 #define SWERV_PIC_meivt "0xBC8"
32 #define SWERV_PIC_meipt "0xBC9"
33 #define SWERV_PIC_meicpct "0xBCA"
34 #define SWERV_PIC_meicidpl "0xBCB"
35 #define SWERV_PIC_meicurpl "0xBCC"
36 #define SWERV_PIC_meihap "0xFC8"
37
38 #define swerv_piccsr(csr) SWERV_PIC_##csr
39
40 #define swerv_pic_readcsr(csr, value) \
41 volatile("csrr %0, "swerv_piccsr(csr) : "=r" (value))
42 #define swerv_pic_writecsr(csr, value) \
43 volatile("csrw "swerv_piccsr(csr)", %0" :: "rK" (value))
44
45 static int save_irq;
46
swerv_pic_read(uint32_t reg)47 static uint32_t swerv_pic_read(uint32_t reg)
48 {
49 return *(volatile uint32_t *)(DT_INST_REG_ADDR(0) + reg);
50 }
51
swerv_pic_write(uint32_t reg,uint32_t val)52 static void swerv_pic_write(uint32_t reg, uint32_t val)
53 {
54 *(volatile uint32_t *)(DT_INST_REG_ADDR(0) + reg) = val;
55 }
56
swerv_pic_irq_enable(uint32_t irq)57 void swerv_pic_irq_enable(uint32_t irq)
58 {
59 uint32_t key;
60
61 if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) {
62 return;
63 }
64
65 key = irq_lock();
66 swerv_pic_write(SWERV_PIC_meie(irq - RISCV_MAX_GENERIC_IRQ), 1);
67 irq_unlock(key);
68 }
69
swerv_pic_irq_disable(uint32_t irq)70 void swerv_pic_irq_disable(uint32_t irq)
71 {
72 uint32_t key;
73
74 if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) {
75 return;
76 }
77
78 key = irq_lock();
79 swerv_pic_write(SWERV_PIC_meie(irq - RISCV_MAX_GENERIC_IRQ), 0);
80 irq_unlock(key);
81 }
82
swerv_pic_irq_is_enabled(uint32_t irq)83 int swerv_pic_irq_is_enabled(uint32_t irq)
84 {
85 if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) {
86 return -1;
87 }
88
89 return swerv_pic_read(SWERV_PIC_meie(irq - RISCV_MAX_GENERIC_IRQ))
90 & 0x1;
91 }
92
swerv_pic_set_priority(uint32_t irq,uint32_t priority)93 void swerv_pic_set_priority(uint32_t irq, uint32_t priority)
94 {
95 uint32_t key;
96
97 if (irq <= RISCV_MAX_GENERIC_IRQ) {
98 return;
99 }
100
101 if ((irq >= SWERV_PIC_MAX_ID) || (irq < RISCV_MAX_GENERIC_IRQ)) {
102 return;
103 }
104
105 if (priority >= SWERV_PIC_MAX_PRIO) {
106 return;
107 }
108
109 key = irq_lock();
110 swerv_pic_write(SWERV_PIC_meipl(irq - RISCV_MAX_GENERIC_IRQ), priority);
111 irq_unlock(key);
112 }
113
swerv_pic_get_irq(void)114 int swerv_pic_get_irq(void)
115 {
116 return save_irq;
117 }
118
swerv_pic_irq_handler(const void * arg)119 static void swerv_pic_irq_handler(const void *arg)
120 {
121 uint32_t tmp;
122 uint32_t irq;
123 struct _isr_table_entry *ite;
124
125 /* trigger the capture of the interrupt source ID */
126 __asm__ swerv_pic_writecsr(meicpct, 0);
127
128 __asm__ swerv_pic_readcsr(meihap, tmp);
129 irq = (tmp >> 2) & 0xff;
130
131 save_irq = irq;
132
133 if (irq == 0U || irq >= 64) {
134 z_irq_spurious(NULL);
135 }
136 irq += RISCV_MAX_GENERIC_IRQ;
137
138 /* Call the corresponding IRQ handler in _sw_isr_table */
139 ite = (struct _isr_table_entry *)&_sw_isr_table[irq];
140 if (ite->isr) {
141 ite->isr(ite->arg);
142 }
143
144 swerv_pic_write(SWERV_PIC_meigwclr(irq), 0);
145 }
146
swerv_pic_init(const struct device * dev)147 static int swerv_pic_init(const struct device *dev)
148 {
149 int i;
150
151 /* Init priority order to 0, 0=lowest to 15=highest */
152 swerv_pic_write(SWERV_PIC_mpiccfg, 0);
153
154 /* Ensure that all interrupts are disabled initially */
155 for (i = 1; i < SWERV_PIC_MAX_ID; i++) {
156 swerv_pic_write(SWERV_PIC_meie(i), 0);
157 }
158
159 /* Set priority of each interrupt line to 0 initially */
160 for (i = 1; i < SWERV_PIC_MAX_ID; i++) {
161 swerv_pic_write(SWERV_PIC_meipl(i), 15);
162 }
163
164 /* Set property of each interrupt line to level-triggered/high */
165 for (i = 1; i < SWERV_PIC_MAX_ID; i++) {
166 swerv_pic_write(SWERV_PIC_meigwctrl(i), (0<<1)|(0<<0));
167 }
168
169 /* clear pending of each interrupt line */
170 for (i = 1; i < SWERV_PIC_MAX_ID; i++) {
171 swerv_pic_write(SWERV_PIC_meigwclr(i), 0);
172 }
173
174 /* No interrupts masked */
175 __asm__ swerv_pic_writecsr(meipt, 0);
176 __asm__ swerv_pic_writecsr(meicidpl, 0);
177 __asm__ swerv_pic_writecsr(meicurpl, 0);
178
179 /* Setup IRQ handler for SweRV PIC driver */
180 IRQ_CONNECT(RISCV_IRQ_MEXT,
181 0,
182 swerv_pic_irq_handler,
183 NULL,
184 0);
185
186 /* Enable IRQ for SweRV PIC driver */
187 irq_enable(RISCV_IRQ_MEXT);
188
189 return 0;
190 }
191
arch_irq_enable(unsigned int irq)192 void arch_irq_enable(unsigned int irq)
193 {
194 uint32_t mie;
195
196 if (irq > RISCV_MAX_GENERIC_IRQ) {
197 swerv_pic_irq_enable(irq);
198 return;
199 }
200
201 /*
202 * CSR mie register is updated using atomic instruction csrrs
203 * (atomic read and set bits in CSR register)
204 */
205 __asm__ volatile ("csrrs %0, mie, %1\n"
206 : "=r" (mie)
207 : "r" (1 << irq));
208 }
209
arch_irq_disable(unsigned int irq)210 void arch_irq_disable(unsigned int irq)
211 {
212 uint32_t mie;
213
214 if (irq > RISCV_MAX_GENERIC_IRQ) {
215 swerv_pic_irq_disable(irq);
216 return;
217 }
218
219 /*
220 * Use atomic instruction csrrc to disable device interrupt in mie CSR.
221 * (atomic read and clear bits in CSR register)
222 */
223 __asm__ volatile ("csrrc %0, mie, %1\n"
224 : "=r" (mie)
225 : "r" (1 << irq));
226 };
227
arch_irq_is_enabled(unsigned int irq)228 int arch_irq_is_enabled(unsigned int irq)
229 {
230 uint32_t mie;
231
232 if (irq > RISCV_MAX_GENERIC_IRQ) {
233 return swerv_pic_irq_is_enabled(irq);
234 }
235
236 __asm__ volatile ("csrr %0, mie" : "=r" (mie));
237
238 return !!(mie & (1 << irq));
239 }
240
241 DEVICE_DT_INST_DEFINE(0, swerv_pic_init, NULL, NULL, NULL,
242 PRE_KERNEL_1, CONFIG_INTC_INIT_PRIORITY, NULL);
243