]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c
Update RISCC-V-RV32-SiFive_HiFive1_FreedomStudio project to latest tools and metal...
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_HiFive1_FreedomStudio / freedom-metal / src / drivers / sifive_clic0.c
1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
3
4 #include <metal/machine/platform.h>
5
6 #ifdef METAL_SIFIVE_CLIC0
7
8 #include <stdint.h>
9 #include <metal/io.h>
10 #include <metal/shutdown.h>
11 #include <metal/drivers/sifive_clic0.h>
12 #include <metal/machine.h>
13
14 typedef enum metal_clic_vector_{
15     METAL_CLIC_NONVECTOR = 0,
16     METAL_CLIC_VECTORED  = 1
17 } metal_clic_vector;
18
19 struct __metal_clic_cfg {
20     unsigned char : 1,
21              nmbits : 2,
22              nlbits : 4,
23               nvbit : 1;
24 };
25
26 const struct __metal_clic_cfg __metal_clic_defaultcfg = {
27                 .nmbits = METAL_INTR_PRIV_M_MODE,
28                 .nlbits = 0,
29                 .nvbit = METAL_CLIC_NONVECTOR
30             };
31
32 void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64)));
33
34 void __metal_clic0_default_vector_handler (void) __attribute__((interrupt, aligned(64)));
35
36 struct __metal_clic_cfg __metal_clic0_configuration (struct __metal_driver_sifive_clic0 *clic,
37                                                  struct __metal_clic_cfg *cfg)
38 {
39     volatile unsigned char val;
40     struct __metal_clic_cfg cliccfg;
41     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
42
43     if ( cfg ) {
44         val = cfg->nmbits << 5 | cfg->nlbits << 1 | cfg->nvbit;
45         __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
46                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
47                                        METAL_SIFIVE_CLIC0_CLICCFG)) = val;
48     }
49     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
50                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
51                                        METAL_SIFIVE_CLIC0_CLICCFG));
52     cliccfg.nmbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK) >> 5;
53     cliccfg.nlbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK) >> 1;
54     cliccfg.nvbit = val & METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK;
55     return cliccfg;
56 }
57
58 int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic, int id, int mode)
59 {
60     uint8_t mask, val;
61     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
62     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
63  
64     if (mode >= (cfg.nmbits << 1)) {
65         /* Do nothing, mode request same or exceed what configured in CLIC */
66         return 0;
67     }
68  
69     /* Mask out nmbits and retain other values */
70     mask = ((uint8_t)(-1)) >> cfg.nmbits;
71     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
72                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
73                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) & mask;
74     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
75                                  METAL_SIFIVE_CLIC0_MMODE_APERTURE +
76                                  METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = val | (mode << (8 - cfg.nmbits));
77     return 0;
78 }
79
80 int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, unsigned int level)
81 {
82     uint8_t mask, nmmask, nlmask, val;
83     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
84     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
85
86     /* Drop the LSBs that don't fit in nlbits */
87     level = level >> (METAL_CLIC_MAX_NLBITS - cfg.nlbits);
88
89     nmmask = ~( ((uint8_t)(-1)) >> (cfg.nmbits) );
90     nlmask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits);
91     mask = ~(nlmask | nmmask);
92   
93     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
94                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
95                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
96     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
97                                  METAL_SIFIVE_CLIC0_MMODE_APERTURE +
98                                  METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, level);
99     return 0;
100 }
101
102 unsigned int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
103 {
104     int level;
105     uint8_t mask, val, freebits, nlbits;
106     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
107     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
108     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
109
110     if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
111         nlbits = num_intbits - cfg.nmbits;
112     } else {
113         nlbits = cfg.nlbits;
114     }
115
116     mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
117     freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
118   
119     if (mask == 0) {
120         level = (1 << METAL_CLIC_MAX_NLBITS) - 1;
121     } else {
122         val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
123                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
124                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
125         val = __METAL_GET_FIELD(val, mask);
126         level = (val << (METAL_CLIC_MAX_NLBITS - nlbits)) | freebits;
127     }
128
129     return level;
130 }
131
132 int __metal_clic0_interrupt_set_priority (struct __metal_driver_sifive_clic0 *clic, int id, int priority)
133 {
134     uint8_t mask, npmask, val, npbits;
135     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
136     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
137     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
138
139     if ((cfg.nmbits + cfg.nlbits) < num_intbits) {
140         npbits = num_intbits - (cfg.nmbits + cfg.nlbits);
141         priority = priority >> (8 - npbits);
142
143         mask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits + npbits);
144         npmask = ~(((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits));
145         mask = ~(mask | npmask);
146
147         val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
148                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
149                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
150         __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
151                                      METAL_SIFIVE_CLIC0_MMODE_APERTURE +
152                                      METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, priority);
153     }
154     return 0;
155 }
156
157 int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *clic, int id)
158 {
159     int priority;
160     uint8_t mask, val, freebits, nlbits;
161     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
162     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
163     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
164
165     if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
166         nlbits = num_intbits - cfg.nmbits;
167     } else {
168         nlbits = cfg.nlbits;
169     }
170
171     mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
172     freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
173     
174     if (mask == 0) {
175         priority = (1 << METAL_CLIC_MAX_NLBITS) - 1;
176     } else {                           
177         val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
178                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
179                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
180         priority = __METAL_GET_FIELD(val, freebits);
181     }
182     return priority;
183 }
184
185 int __metal_clic0_interrupt_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, int id, int enable)
186 {   
187     uint8_t mask, val;
188     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
189     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
190
191     mask = 1 << (8 - num_intbits);
192     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
193                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
194                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
195     /* Ensure its value is 1 bit wide */
196     enable &= 0x1;
197     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
198                                  METAL_SIFIVE_CLIC0_MMODE_APERTURE +
199                                  METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, enable);
200     return 0;
201 }
202
203 int __metal_clic0_interrupt_is_vectored (struct __metal_driver_sifive_clic0 *clic, int id)
204 {
205     uint8_t mask, val;
206     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
207     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
208
209     mask = 1 << (8 - num_intbits);
210     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
211                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
212                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
213     return __METAL_GET_FIELD(val, mask);
214 }
215
216 int __metal_clic0_interrupt_enable (struct __metal_driver_sifive_clic0 *clic, int id)
217 {
218     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
219     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
220
221     if (id >= num_subinterrupts) {
222         return -1;
223     }
224     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
225                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
226                                        METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_ENABLE;
227     return 0;
228 }
229
230 int __metal_clic0_interrupt_disable (struct __metal_driver_sifive_clic0 *clic, int id)
231 {
232     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
233     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
234
235     if (id >= num_subinterrupts) {
236         return -1;
237     }
238     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
239                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
240                                        METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_DISABLE;
241     return 0;
242 }
243
244 int __metal_clic0_interrupt_is_enabled (struct __metal_driver_sifive_clic0 *clic, int id)
245 {
246     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
247     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
248
249     if (id >= num_subinterrupts) {
250         return 0;
251     }
252     return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
253                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
254                                        METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id));
255 }
256
257 int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic, int id)
258 {
259     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
260     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
261
262     if (id >= num_subinterrupts) {
263         return 0;
264     }
265     return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
266                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
267                                        METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id));
268 }
269
270 int __metal_clic0_interrupt_set (struct __metal_driver_sifive_clic0 *clic, int id)
271 {       
272     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
273     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
274
275     if (id < num_subinterrupts) {
276         __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
277                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE + 
278                                        METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_ENABLE;
279         return 0;
280     }
281     return -1;
282 }
283
284 int __metal_clic0_interrupt_clear (struct __metal_driver_sifive_clic0 *clic, int id)
285 {
286     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
287     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
288
289     if (id < num_subinterrupts) {
290         __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
291                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
292                                        METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id)) = METAL_DISABLE;
293         return 0;
294     }
295     return -1;
296 }
297
298 int __metal_clic0_configure_set_vector_mode (struct __metal_driver_sifive_clic0 *clic, metal_vector_mode mode)
299 {
300     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
301
302     switch (mode) {
303     case METAL_SELECTIVE_NONVECTOR_MODE:
304         cfg.nvbit = METAL_CLIC_NONVECTOR;
305         __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
306         break;
307     case METAL_SELECTIVE_VECTOR_MODE:
308         cfg.nvbit = METAL_CLIC_VECTORED;
309         __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
310         break;
311     case METAL_HARDWARE_VECTOR_MODE:
312         cfg.nvbit = METAL_CLIC_VECTORED;
313         __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
314         break;
315     default:
316         return -1;
317     }
318     __metal_clic0_configuration(clic, &cfg);
319     return 0;
320 }
321
322 metal_vector_mode __metal_clic0_configure_get_vector_mode (struct __metal_driver_sifive_clic0 *clic)
323 {
324     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
325     metal_vector_mode mode = __metal_controller_interrupt_vector_mode();
326
327     if (mode == METAL_SELECTIVE_VECTOR_MODE) { 
328         if (cfg.nvbit) {
329             return METAL_SELECTIVE_VECTOR_MODE;
330         } else {
331             return METAL_SELECTIVE_NONVECTOR_MODE;
332         }
333     } else {
334         return mode;
335     }
336 }
337
338 int __metal_clic0_configure_set_privilege (struct __metal_driver_sifive_clic0 *clic, metal_intr_priv_mode priv)
339 {
340     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
341
342     cfg.nmbits = priv;
343     __metal_clic0_configuration(clic, &cfg);
344     return 0;
345 }
346
347 metal_intr_priv_mode __metal_clic0_configure_get_privilege (struct __metal_driver_sifive_clic0 *clic)
348 {
349     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
350
351     return cfg.nmbits;
352 }
353
354 int __metal_clic0_configure_set_level (struct __metal_driver_sifive_clic0 *clic, int level)
355 {
356     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
357
358     cfg.nlbits = level & 0xF;
359     __metal_clic0_configuration(clic, &cfg);
360     return 0;
361 }
362
363 int __metal_clic0_configure_get_level (struct __metal_driver_sifive_clic0 *clic)
364 {
365     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
366
367     return cfg.nlbits;
368 }
369
370 unsigned long long __metal_clic0_mtime_get (struct __metal_driver_sifive_clic0 *clic)
371 {
372     __metal_io_u32 lo, hi;
373     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
374
375     /* Guard against rollover when reading */
376     do {
377         hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4));
378         lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME));
379     } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4)) != hi);
380
381     return (((unsigned long long)hi) << 32) | lo;
382 }
383
384 int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller,
385                                              int hartid,
386                                              unsigned long long time)
387 {   
388     struct __metal_driver_sifive_clic0 *clic =
389                               (struct __metal_driver_sifive_clic0 *)(controller);
390
391     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
392     /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit,
393      * and are NOT internally latched for multiword transfers.
394      * Need to be careful about sequencing to avoid triggering
395      * spurious interrupts: For that set the high word to a max
396      * value first.
397      */
398     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF;
399     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE)) = (__metal_io_u32)time;
400     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32);
401     return 0;
402 }
403
404 void __metal_clic0_handler (int id, void *priv)
405 {
406     struct __metal_driver_sifive_clic0 *clic = priv;
407     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
408
409     if ( (id < num_subinterrupts) && (clic->metal_exint_table[id].handler) ) {
410         clic->metal_exint_table[id].handler(id, clic->metal_exint_table[id].exint_data);
411     }
412 }
413
414 void __metal_clic0_default_handler (int id, void *priv) {
415     metal_shutdown(300);
416 }
417
418 void __metal_clic0_default_vector_handler (void) {
419     metal_shutdown(400);
420 }
421
422 void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
423 {
424     struct __metal_driver_sifive_clic0 *clic =
425                               (struct __metal_driver_sifive_clic0 *)(controller);
426
427     if ( !clic->init_done ) {
428         int level, max_levels, line, num_interrupts, num_subinterrupts;
429         struct __metal_clic_cfg cfg = __metal_clic_defaultcfg;
430         struct metal_interrupt *intc =
431             __metal_driver_sifive_clic0_interrupt_parent(controller);
432
433         /* Initialize ist parent controller, aka cpu_intc. */
434         intc->vtable->interrupt_init(intc);
435         __metal_controller_interrupt_vector(METAL_SELECTIVE_NONVECTOR_MODE,
436                                             &clic->metal_mtvt_table);
437
438         /*
439          * Register its interrupts with with parent controller,
440          * aka sw, timer and ext to its default isr
441          */
442         num_interrupts = __metal_driver_sifive_clic0_num_interrupts(controller);
443         for (int i = 0; i < num_interrupts; i++) {
444             line = __metal_driver_sifive_clic0_interrupt_lines(controller, i);
445             intc->vtable->interrupt_register(intc, line, NULL, clic);
446         }
447
448         /* Default CLIC mode to per dts */
449         max_levels = __metal_driver_sifive_clic0_max_levels(controller);
450         cfg.nlbits = (max_levels > METAL_CLIC_MAX_NLBITS) ?
451                                 METAL_CLIC_MAX_NLBITS : max_levels;
452         __metal_clic0_configuration(clic, &cfg);
453
454         level = (1 << cfg.nlbits) - 1;
455         num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
456         clic->metal_mtvt_table[0] = &__metal_clic0_handler;
457         for (int i = 1; i < num_subinterrupts; i++) {
458             clic->metal_mtvt_table[i] = NULL;
459             clic->metal_exint_table[i].handler = NULL;
460             clic->metal_exint_table[i].sub_int = NULL;
461             clic->metal_exint_table[i].exint_data = NULL;
462             __metal_clic0_interrupt_disable(clic, i);
463             __metal_clic0_interrupt_set_level(clic, i, level);
464         }
465         clic->init_done = 1;
466     }   
467 }
468
469 int __metal_driver_sifive_clic0_register (struct metal_interrupt *controller,
470                                         int id, metal_interrupt_handler_t isr,
471                                         void *priv)
472 {   
473     int rc = -1;
474     int num_subinterrupts;
475     struct __metal_driver_sifive_clic0 *clic =
476                               (struct __metal_driver_sifive_clic0 *)(controller);
477     struct metal_interrupt *intc =
478                        __metal_driver_sifive_clic0_interrupt_parent(controller);
479     metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
480     
481     if ( ( (mode == METAL_SELECTIVE_VECTOR_MODE) &&
482            (__metal_clic0_interrupt_is_vectored(clic, id)) ) ||
483          (mode == METAL_HARDWARE_VECTOR_MODE) ||
484          (mode == METAL_VECTOR_MODE) ||
485          (mode == METAL_DIRECT_MODE) ) {
486         return rc;
487     }
488
489     /* Register its interrupts with parent controller */
490     if (id < METAL_INTERRUPT_ID_CSW) {
491         return intc->vtable->interrupt_register(intc, id, isr, priv);
492     }
493     
494     /* 
495      * CLIC (sub-interrupts) devices interrupts start at 16 but offset from 0
496      * Reset the IDs to reflects this.
497      */
498     num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
499     if (id < num_subinterrupts) {
500         if ( isr) {
501             clic->metal_exint_table[id].handler = isr;
502             clic->metal_exint_table[id].exint_data = priv;
503         } else {
504             clic->metal_exint_table[id].handler = __metal_clic0_default_handler;
505             clic->metal_exint_table[id].sub_int = priv;
506         }
507         rc = 0;
508     }
509     return rc;
510 }
511
512 int __metal_driver_sifive_clic0_vector_register (struct metal_interrupt *controller,
513                                                  int id, metal_interrupt_vector_handler_t isr,
514                                                  void *priv)
515 {
516     int rc = -1;
517     struct __metal_driver_sifive_clic0 *clic =
518                               (struct __metal_driver_sifive_clic0 *)(controller);
519     struct metal_interrupt *intc =
520                        __metal_driver_sifive_clic0_interrupt_parent(controller);
521     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
522     metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
523
524     if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
525         return rc;
526     }
527     if ((mode == METAL_SELECTIVE_VECTOR_MODE) &&
528         (__metal_clic0_interrupt_is_vectored(clic, id) == 0) ) {
529         return rc;
530     }
531     if (id < num_subinterrupts) {
532         if ( isr) {
533             clic->metal_mtvt_table[id] = isr;
534             clic->metal_exint_table[id].exint_data = priv;        
535         } else {
536             clic->metal_mtvt_table[id] = __metal_clic0_default_vector_handler;
537             clic->metal_exint_table[id].sub_int = priv;
538         }
539         rc = 0;
540     }
541     return rc;
542 }
543
544 int __metal_driver_sifive_clic0_enable (struct metal_interrupt *controller, int id)
545 {
546     struct __metal_driver_sifive_clic0 *clic =
547                               (struct __metal_driver_sifive_clic0 *)(controller);
548     return __metal_clic0_interrupt_enable(clic, id);
549 }
550
551 int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int id)
552 {
553     struct __metal_driver_sifive_clic0 *clic =
554                               (struct __metal_driver_sifive_clic0 *)(controller);
555     return __metal_clic0_interrupt_disable(clic, id);
556 }
557
558 int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller, int id)
559 {
560     int rc = -1;
561     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
562     struct __metal_driver_sifive_clic0 *clic =
563                               (struct __metal_driver_sifive_clic0 *)(controller);
564     metal_vector_mode mode = __metal_clic0_configure_get_vector_mode(clic);
565
566     if ((mode != METAL_SELECTIVE_VECTOR_MODE) && (mode != METAL_HARDWARE_VECTOR_MODE)) {
567         return rc;
568     }
569     if (id < num_subinterrupts) {
570         __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_ENABLE);
571         return 0;
572     }
573     return -1;
574 }
575
576 int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt *controller, int id)
577 {
578     int num_subinterrupts;
579     struct __metal_driver_sifive_clic0 *clic =
580                               (struct __metal_driver_sifive_clic0 *)(controller);
581
582     num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
583     if (id < num_subinterrupts) {
584         __metal_clic0_interrupt_set_vector_mode(clic, id, METAL_DISABLE);
585         return 0;
586     }
587     return -1;
588 }
589
590 metal_vector_mode __metal_driver_sifive_clic0_get_vector_mode (struct metal_interrupt *controller)
591 {
592     struct __metal_driver_sifive_clic0 *clic =
593                               (struct __metal_driver_sifive_clic0 *)(controller);
594     return __metal_clic0_configure_get_vector_mode(clic);
595 }
596
597 int __metal_driver_sifive_clic0_set_vector_mode (struct metal_interrupt *controller, metal_vector_mode mode)
598 {
599     struct __metal_driver_sifive_clic0 *clic =
600                               (struct __metal_driver_sifive_clic0 *)(controller);
601     return __metal_clic0_configure_set_vector_mode(clic, mode);
602 }
603
604 metal_intr_priv_mode  __metal_driver_sifive_clic0_get_privilege (struct metal_interrupt *controller)
605 {
606     struct __metal_driver_sifive_clic0 *clic =
607                               (struct __metal_driver_sifive_clic0 *)(controller);
608     return __metal_clic0_configure_get_privilege(clic);
609 }
610
611 int __metal_driver_sifive_clic0_set_privilege (struct metal_interrupt *controller, metal_intr_priv_mode priv)
612 {
613     struct __metal_driver_sifive_clic0 *clic =
614                               (struct __metal_driver_sifive_clic0 *)(controller);
615     return __metal_clic0_configure_set_privilege(clic, priv);
616 }
617
618 unsigned int __metal_driver_sifive_clic0_get_threshold (struct metal_interrupt *controller)
619 {
620     struct __metal_driver_sifive_clic0 *clic =
621                               (struct __metal_driver_sifive_clic0 *)(controller);
622     return __metal_clic0_configure_get_level(clic);
623 }
624
625 int __metal_driver_sifive_clic0_set_threshold (struct metal_interrupt *controller, unsigned int level)
626 {
627     struct __metal_driver_sifive_clic0 *clic =
628                               (struct __metal_driver_sifive_clic0 *)(controller);
629     return __metal_clic0_configure_set_level(clic, level);
630 }
631
632 unsigned int __metal_driver_sifive_clic0_get_priority (struct metal_interrupt *controller, int id)
633 {   
634     struct __metal_driver_sifive_clic0 *clic =
635                               (struct __metal_driver_sifive_clic0 *)(controller);
636     return __metal_clic0_interrupt_get_priority(clic, id);
637 }
638
639 int __metal_driver_sifive_clic0_set_priority (struct metal_interrupt *controller, int id, unsigned int priority)
640 {   
641     struct __metal_driver_sifive_clic0 *clic =
642                               (struct __metal_driver_sifive_clic0 *)(controller);
643     return __metal_clic0_interrupt_set_priority(clic, id, priority);
644 }
645
646 int __metal_driver_sifive_clic0_clear_interrupt (struct metal_interrupt *controller, int id)
647 {
648     struct __metal_driver_sifive_clic0 *clic =
649                               (struct __metal_driver_sifive_clic0 *)(controller);
650     return __metal_clic0_interrupt_clear(clic, id);
651 }
652
653 int __metal_driver_sifive_clic0_set_interrupt (struct metal_interrupt *controller, int id)
654 {
655     struct __metal_driver_sifive_clic0 *clic =
656                               (struct __metal_driver_sifive_clic0 *)(controller);
657     return __metal_clic0_interrupt_set(clic, id);
658 }
659
660 int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *controller,
661                                                int command, void *data)
662 {
663     int hartid;
664     int rc = -1;
665     struct __metal_driver_sifive_clic0 *clic =
666                               (struct __metal_driver_sifive_clic0 *)(controller);
667     unsigned long control_base = __metal_driver_sifive_clic0_control_base(controller);
668
669     switch (command) {
670     case METAL_TIMER_MTIME_GET:
671         if (data) {
672             *(unsigned long long *)data = __metal_clic0_mtime_get(clic);
673             rc = 0;
674         }
675         break;
676     case METAL_SOFTWARE_IPI_CLEAR:
677         if (data) {
678             hartid = *(int *)data;
679             __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
680                                                (hartid * 4))) = METAL_DISABLE;
681            __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
682                                               METAL_SIFIVE_CLIC0_MMODE_APERTURE +
683                                               METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_DISABLE;
684             rc = 0;
685         }
686         break;
687     case METAL_SOFTWARE_IPI_SET:
688         if (data) {
689             hartid = *(int *)data;
690             __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
691                                                (hartid * 4))) = METAL_ENABLE;
692             __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
693                                                METAL_SIFIVE_CLIC0_MMODE_APERTURE +
694                                                METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_ENABLE;
695             rc = 0;
696         }
697         break;
698     case METAL_SOFTWARE_MSIP_GET:
699         rc = 0;
700         if (data) {
701             hartid = *(int *)data;
702             rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
703                                                     (hartid * 4)));
704         }
705         break;
706     default:
707         break;
708     }
709
710     return rc;
711 }
712 __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_clic0) = {
713     .clic_vtable.interrupt_init     = __metal_driver_sifive_clic0_init,
714     .clic_vtable.interrupt_register = __metal_driver_sifive_clic0_register,
715     .clic_vtable.interrupt_vector_register = __metal_driver_sifive_clic0_vector_register,
716     .clic_vtable.interrupt_enable   = __metal_driver_sifive_clic0_enable,
717     .clic_vtable.interrupt_disable  = __metal_driver_sifive_clic0_disable,
718     .clic_vtable.interrupt_vector_enable   = __metal_driver_sifive_clic0_enable_interrupt_vector,
719     .clic_vtable.interrupt_vector_disable  = __metal_driver_sifive_clic0_disable_interrupt_vector,
720     .clic_vtable.interrupt_get_vector_mode = __metal_driver_sifive_clic0_get_vector_mode,
721     .clic_vtable.interrupt_set_vector_mode = __metal_driver_sifive_clic0_set_vector_mode,
722     .clic_vtable.interrupt_get_privilege   = __metal_driver_sifive_clic0_get_privilege,
723     .clic_vtable.interrupt_set_privilege   = __metal_driver_sifive_clic0_set_privilege,
724     .clic_vtable.interrupt_get_threshold   = __metal_driver_sifive_clic0_get_threshold,
725     .clic_vtable.interrupt_set_threshold   = __metal_driver_sifive_clic0_set_threshold,
726     .clic_vtable.interrupt_get_priority    = __metal_driver_sifive_clic0_get_priority,
727     .clic_vtable.interrupt_set_priority    = __metal_driver_sifive_clic0_set_priority,
728     .clic_vtable.interrupt_clear    = __metal_driver_sifive_clic0_clear_interrupt,
729     .clic_vtable.interrupt_set      = __metal_driver_sifive_clic0_set_interrupt,
730     .clic_vtable.command_request    = __metal_driver_sifive_clic0_command_request,
731     .clic_vtable.mtimecmp_set       = __metal_driver_sifive_clic0_mtimecmp_set,
732 };
733
734 #endif /* METAL_SIFIVE_CLIC0 */
735
736 typedef int no_empty_translation_units;