]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/sifive_clic0.c
Rename the RISC-V_RV32_SiFive_Hifive1_GCC folder to RISC-V_RV32_SiFive_HiFive1_Freedo...
[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_priv_mode_ {
15     METAL_PRIV_M_MODE = 0,
16     METAL_PRIV_MU_MODE = 1,
17     METAL_PRIV_MSU_MODE = 2
18 } metal_priv_mode;
19
20 typedef enum metal_clic_vector_{
21     METAL_CLIC_NONVECTOR = 0,
22     METAL_CLIC_VECTORED  = 1
23 } metal_clic_vector;
24
25 struct __metal_clic_cfg {
26     unsigned char : 1,
27              nmbits : 2,
28              nlbits : 4,
29               nvbit : 1;
30 };
31
32 const struct __metal_clic_cfg __metal_clic_defaultcfg = {
33                 .nmbits = METAL_PRIV_M_MODE,
34                 .nlbits = 0,
35                 .nvbit = METAL_CLIC_NONVECTOR
36             };
37
38 struct __metal_clic_cfg __metal_clic0_configuration (struct __metal_driver_sifive_clic0 *clic,
39                                                  struct __metal_clic_cfg *cfg)
40 {
41     volatile unsigned char val;
42     struct __metal_clic_cfg cliccfg;
43     uintptr_t hartid = __metal_myhart_id();
44     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
45
46     if ( cfg ) {
47         val = cfg->nmbits << 5 | cfg->nlbits << 1 | cfg->nvbit;
48         __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
49                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
50                                        METAL_SIFIVE_CLIC0_CLICCFG)) = val;
51     }
52     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
53                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
54                                        METAL_SIFIVE_CLIC0_CLICCFG));
55     cliccfg.nmbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NMBITS_MASK) >> 5;
56     cliccfg.nlbits = (val & METAL_SIFIVE_CLIC0_CLICCFG_NLBITS_MASK) >> 1;
57     cliccfg.nvbit = val & METAL_SIFIVE_CLIC0_CLICCFG_NVBIT_MASK;
58     return cliccfg;
59 }
60
61 int __metal_clic0_interrupt_set_mode (struct __metal_driver_sifive_clic0 *clic, int id, int mode)
62 {
63     uint8_t mask, val;
64     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
65     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
66  
67     if (mode >= (cfg.nmbits << 1)) {
68         /* Do nothing, mode request same or exceed what configured in CLIC */
69         return 0;
70     }
71  
72     /* Mask out nmbits and retain other values */
73     mask = ((uint8_t)(-1)) >> cfg.nmbits;
74     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
75                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
76                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) & mask;
77     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
78                                  METAL_SIFIVE_CLIC0_MMODE_APERTURE +
79                                  METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = val | (mode << (8 - cfg.nmbits));
80     return 0;
81 }
82
83 int __metal_clic0_interrupt_set_level (struct __metal_driver_sifive_clic0 *clic, int id, int level)
84 {
85     uint8_t mask, nmmask, nlmask, val;
86     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
87     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
88
89     /* Drop the LSBs that don't fit in nlbits */
90     level = level >> (METAL_CLIC_MAX_NLBITS - cfg.nlbits);
91
92     nmmask = ~( ((uint8_t)(-1)) >> (cfg.nmbits) );
93     nlmask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits);
94     mask = ~(nlmask | nmmask);
95   
96     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
97                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
98                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
99     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
100                                  METAL_SIFIVE_CLIC0_MMODE_APERTURE +
101                                  METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, level);
102     return 0;
103 }
104
105 int __metal_clic0_interrupt_get_level (struct __metal_driver_sifive_clic0 *clic, int id)
106 {
107     int level;
108     uint8_t mask, val, freebits, nlbits;
109     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
110     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
111     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
112
113     if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
114         nlbits = num_intbits - cfg.nmbits;
115     } else {
116         nlbits = cfg.nlbits;
117     }
118
119     mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
120     freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
121   
122     if (mask == 0) {
123         level = (1 << METAL_CLIC_MAX_NLBITS) - 1;
124     } else {
125         val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
126                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
127                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
128         val = __METAL_GET_FIELD(val, mask);
129         level = (val << (METAL_CLIC_MAX_NLBITS - nlbits)) | freebits;
130     }
131
132     return level;
133 }
134
135 int __metal_clic0_interrupt_set_priority (struct __metal_driver_sifive_clic0 *clic, int id, int priority)
136 {
137     uint8_t mask, npmask, val, npbits;
138     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
139     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
140     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
141
142     if ((cfg.nmbits + cfg.nlbits) < num_intbits) {
143         npbits = num_intbits - (cfg.nmbits + cfg.nlbits);
144         priority = priority >> (8 - npbits);
145
146         mask = ((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits + npbits);
147         npmask = ~(((uint8_t)(-1)) >> (cfg.nmbits + cfg.nlbits));
148         mask = ~(mask | npmask);
149
150         val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
151                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
152                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
153         __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
154                                      METAL_SIFIVE_CLIC0_MMODE_APERTURE +
155                                      METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, priority);
156     }
157     return 0;
158 }
159
160 int __metal_clic0_interrupt_get_priority (struct __metal_driver_sifive_clic0 *clic, int id)
161 {
162     int priority;
163     uint8_t mask, val, freebits, nlbits;
164     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
165     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
166     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
167
168     if ((cfg.nmbits + cfg.nlbits) >= num_intbits) {
169         nlbits = num_intbits - cfg.nmbits;
170     } else {
171         nlbits = cfg.nlbits;
172     }
173
174     mask = ((1 << nlbits) - 1) << (8 - (cfg.nmbits + nlbits));
175     freebits = ((1 << METAL_CLIC_MAX_NLBITS) - 1) >> nlbits;
176     
177     if (mask == 0) {
178         priority = (1 << METAL_CLIC_MAX_NLBITS) - 1;
179     } else {                           
180         val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
181                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
182                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
183         priority = __METAL_GET_FIELD(val, freebits);
184     }
185     return priority;
186 }
187
188 int __metal_clic0_interrupt_set_vector (struct __metal_driver_sifive_clic0 *clic, int id, int enable)
189 {   
190     uint8_t mask, val;
191     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
192     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
193
194     mask = 1 << (8 - num_intbits);
195     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
196                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
197                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
198     /* Ensure its value is 1 bit wide */
199     enable &= 0x1;
200     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
201                                  METAL_SIFIVE_CLIC0_MMODE_APERTURE +
202                                  METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id)) = __METAL_SET_FIELD(val, mask, enable);
203     return 0;
204 }
205
206 int __metal_clic0_interrupt_is_vectored (struct __metal_driver_sifive_clic0 *clic, int id)
207 {
208     uint8_t mask, val;
209     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
210     int num_intbits = __metal_driver_sifive_clic0_num_intbits((struct metal_interrupt *)clic);
211
212     mask = 1 << (8 - num_intbits);
213     val = __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
214                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
215                                        METAL_SIFIVE_CLIC0_CLICINTCTL_BASE + id));
216     return __METAL_GET_FIELD(val, mask);
217 }
218
219 int __metal_clic0_interrupt_enable (struct __metal_driver_sifive_clic0 *clic, int id)
220 {
221     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
222     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
223
224     if (id >= num_subinterrupts) {
225         return -1;
226     }
227     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
228                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
229                                        METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_ENABLE;
230     return 0;
231 }
232
233 int __metal_clic0_interrupt_disable (struct __metal_driver_sifive_clic0 *clic, int id)
234 {
235     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
236     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
237
238     if (id >= num_subinterrupts) {
239         return -1;
240     }
241     __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
242                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
243                                        METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id)) = METAL_DISABLE;
244     return 0;
245 }
246
247 int __metal_clic0_interrupt_is_enabled (struct __metal_driver_sifive_clic0 *clic, int id)
248 {
249     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
250     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
251
252     if (id >= num_subinterrupts) {
253         return 0;
254     }
255     return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
256                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
257                                        METAL_SIFIVE_CLIC0_CLICINTIE_BASE + id));
258 }
259
260 int __metal_clic0_interrupt_is_pending (struct __metal_driver_sifive_clic0 *clic, int id)
261 {
262     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
263     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
264
265     if (id >= num_subinterrupts) {
266         return 0;
267     }
268     return __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
269                                        METAL_SIFIVE_CLIC0_MMODE_APERTURE +
270                                        METAL_SIFIVE_CLIC0_CLICINTIP_BASE + id));
271 }
272
273 int __metal_clic0_interrupt_set (struct __metal_driver_sifive_clic0 *clic, int id)
274 {       
275     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
276
277     if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
278     }
279     return 0;
280 }
281
282 int __metal_clic0_interrupt_clear (struct __metal_driver_sifive_clic0 *clic, int id)
283 {
284     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
285
286     if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
287     }
288     return 0;
289 }
290
291 void __metal_clic0_configure_privilege (struct __metal_driver_sifive_clic0 *clic, metal_priv_mode priv)
292 {
293     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
294
295     cfg.nmbits = priv;
296     __metal_clic0_configuration(clic, &cfg);
297 }
298
299 void __metal_clic0_configure_level (struct __metal_driver_sifive_clic0 *clic, int level)
300 {
301     struct __metal_clic_cfg cfg = __metal_clic0_configuration(clic, NULL);
302
303     cfg.nlbits = level;
304     __metal_clic0_configuration(clic, &cfg);
305 }
306
307 unsigned long long __metal_clic0_mtime_get (struct __metal_driver_sifive_clic0 *clic)
308 {
309     __metal_io_u32 lo, hi;
310     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
311
312     /* Guard against rollover when reading */
313     do {
314         hi = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4));
315         lo = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME));
316     } while (__METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + METAL_SIFIVE_CLIC0_MTIME + 4)) != hi);
317
318     return (((unsigned long long)hi) << 32) | lo;
319 }
320
321 int __metal_driver_sifive_clic0_mtimecmp_set(struct metal_interrupt *controller,
322                                              int hartid,
323                                              unsigned long long time)
324 {   
325     struct __metal_driver_sifive_clic0 *clic =
326                               (struct __metal_driver_sifive_clic0 *)(controller);
327
328     unsigned long control_base = __metal_driver_sifive_clic0_control_base((struct metal_interrupt *)clic);
329     /* Per spec, the RISC-V MTIME/MTIMECMP registers are 64 bit,
330      * and are NOT internally latched for multiword transfers.
331      * Need to be careful about sequencing to avoid triggering
332      * spurious interrupts: For that set the high word to a max
333      * value first.
334      */
335     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = 0xFFFFFFFF;
336     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE)) = (__metal_io_u32)time;
337     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base + (8 * hartid) + METAL_SIFIVE_CLIC0_MTIMECMP_BASE + 4)) = (__metal_io_u32)(time >> 32);
338     return 0;
339 }
340
341 void __metal_clic0_handler(int id, void *priv) __attribute__((aligned(64)));
342 void __metal_clic0_handler (int id, void *priv)
343 {
344     int idx;
345     struct __metal_driver_sifive_clic0 *clic = priv;
346     int num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts((struct metal_interrupt *)clic);
347
348     idx = id - METAL_INTERRUPT_ID_LC0;
349     if ( (idx < num_subinterrupts) && (clic->metal_mtvt_table[idx]) ) {
350         clic->metal_mtvt_table[idx](id, clic->metal_exint_table[idx].exint_data);
351     }
352 }
353
354 void __metal_clic0_default_handler (int id, void *priv) {
355     metal_shutdown(300);
356 }
357
358 void __metal_driver_sifive_clic0_init (struct metal_interrupt *controller)
359 {
360     struct __metal_driver_sifive_clic0 *clic =
361                               (struct __metal_driver_sifive_clic0 *)(controller);
362
363     if ( !clic->init_done ) {
364         int level, max_levels, line, num_interrupts, num_subinterrupts;
365         struct __metal_clic_cfg cfg = __metal_clic_defaultcfg;
366         struct metal_interrupt *intc =
367             __metal_driver_sifive_clic0_interrupt_parent(controller);
368
369         /* Initialize ist parent controller, aka cpu_intc. */
370         intc->vtable->interrupt_init(intc);
371         __metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE,
372                                           &__metal_clic0_handler);
373
374         /*
375          * Register its interrupts with with parent controller,
376          * aka sw, timer and ext to its default isr
377          */
378         num_interrupts = __metal_driver_sifive_clic0_num_interrupts(controller);
379         for (int i = 0; i < num_interrupts; i++) {
380             line = __metal_driver_sifive_clic0_interrupt_lines(controller, i);
381             intc->vtable->interrupt_register(intc, line, NULL, clic);
382         }
383
384         /* Default CLIC mode to per dts */
385         max_levels = __metal_driver_sifive_clic0_max_levels(controller);
386         cfg.nlbits = (max_levels > METAL_CLIC_MAX_NLBITS) ?
387                                 METAL_CLIC_MAX_NLBITS : max_levels;
388         __metal_clic0_configuration(clic, &cfg);
389
390         level = (1 << cfg.nlbits) - 1;
391         num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
392         for (int i = 0; i < num_subinterrupts; i++) {
393             clic->metal_mtvt_table[i] = NULL;
394             clic->metal_exint_table[i].sub_int = NULL;
395             clic->metal_exint_table[i].exint_data = NULL;
396             __metal_clic0_interrupt_disable(clic, i);
397             __metal_clic0_interrupt_set_level(clic, i, level);
398         }
399         clic->init_done = 1;
400     }   
401 }
402
403 int __metal_driver_sifive_clic0_register (struct metal_interrupt *controller,
404                                         int id, metal_interrupt_handler_t isr,
405                                         void *priv)
406 {
407     int rc = -1;
408     int num_subinterrupts;
409     struct __metal_driver_sifive_clic0 *clic =
410                               (struct __metal_driver_sifive_clic0 *)(controller);
411     struct metal_interrupt *intc =
412                        __metal_driver_sifive_clic0_interrupt_parent(controller);
413
414     /* Register its interrupts with parent controller */
415     if ( id < METAL_INTERRUPT_ID_LC0) {
416         return intc->vtable->interrupt_register(intc, id, isr, priv);
417     }
418
419     /*
420      * CLIC (sub-interrupts) devices interrupts start at 16 but offset from 0
421      * Reset the IDs to reflects this. 
422      */
423     id -= METAL_INTERRUPT_ID_LC0;
424     num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
425     if (id < num_subinterrupts) {
426         if ( isr) {
427             clic->metal_mtvt_table[id] = isr;
428             clic->metal_exint_table[id].exint_data = priv;        
429         } else {
430             clic->metal_mtvt_table[id] = __metal_clic0_default_handler;
431             clic->metal_exint_table[id].sub_int = priv;
432         }
433         rc = 0;
434     }
435     return rc;
436 }
437
438 int __metal_driver_sifive_clic0_enable (struct metal_interrupt *controller, int id)
439 {
440     struct __metal_driver_sifive_clic0 *clic =
441                               (struct __metal_driver_sifive_clic0 *)(controller);
442     return __metal_clic0_interrupt_enable(clic, id);
443 }
444
445 int __metal_driver_sifive_clic0_disable (struct metal_interrupt *controller, int id)
446 {
447     struct __metal_driver_sifive_clic0 *clic =
448                               (struct __metal_driver_sifive_clic0 *)(controller);
449     return __metal_clic0_interrupt_disable(clic, id);
450 }
451
452 int __metal_driver_sifive_clic0_enable_interrupt_vector(struct metal_interrupt *controller,
453                                                       int id, metal_vector_mode mode)
454 {
455     int num_subinterrupts;
456     struct __metal_driver_sifive_clic0 *clic =
457                               (struct __metal_driver_sifive_clic0 *)(controller);
458
459     if (id == METAL_INTERRUPT_ID_BASE) {
460         if (mode == METAL_SELECTIVE_VECTOR_MODE) {
461             __metal_controller_interrupt_vector(mode, &__metal_clic0_handler);
462             return 0;
463         }
464         if (mode == METAL_HARDWARE_VECTOR_MODE) {
465             __metal_controller_interrupt_vector(mode, &clic->metal_mtvt_table);
466             return 0;
467         }
468     }
469     num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
470     if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
471         if ((mode == METAL_SELECTIVE_VECTOR_MODE) &&
472              __metal_controller_interrupt_is_selective_vectored()) {
473             __metal_clic0_interrupt_set_vector(clic, id, METAL_ENABLE);
474             return 0;
475         }
476
477     }
478     return -1;
479 }
480
481 int __metal_driver_sifive_clic0_disable_interrupt_vector(struct metal_interrupt *controller, int id)
482 {
483     int num_subinterrupts;
484     struct __metal_driver_sifive_clic0 *clic =
485                               (struct __metal_driver_sifive_clic0 *)(controller);
486
487     if (id == METAL_INTERRUPT_ID_BASE) {
488         __metal_controller_interrupt_vector(METAL_SELECTIVE_VECTOR_MODE, &__metal_clic0_handler);
489         return 0;
490     }
491     num_subinterrupts = __metal_driver_sifive_clic0_num_subinterrupts(controller);
492     if ((id >= METAL_INTERRUPT_ID_LC0) && (id < num_subinterrupts)) {
493         if  (__metal_controller_interrupt_is_selective_vectored()) {
494             __metal_clic0_interrupt_set_vector(clic, id, METAL_DISABLE);
495             return 0;
496         }
497     }
498     return -1;
499 }
500
501 int __metal_driver_sifive_clic0_command_request (struct metal_interrupt *controller,
502                                                int command, void *data)
503 {
504     int hartid;
505     int rc = -1;
506     struct __metal_driver_sifive_clic0 *clic =
507                               (struct __metal_driver_sifive_clic0 *)(controller);
508     unsigned long control_base = __metal_driver_sifive_clic0_control_base(controller);
509
510     switch (command) {
511     case METAL_TIMER_MTIME_GET:
512         if (data) {
513             *(unsigned long long *)data = __metal_clic0_mtime_get(clic);
514             rc = 0;
515         }
516         break;
517     case METAL_SOFTWARE_IPI_CLEAR:
518         if (data) {
519             hartid = *(int *)data;
520             __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
521                                                (hartid * 4))) = METAL_DISABLE;
522            __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
523                                               METAL_SIFIVE_CLIC0_MMODE_APERTURE +
524                                               METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_DISABLE;
525             rc = 0;
526         }
527         break;
528     case METAL_SOFTWARE_IPI_SET:
529         if (data) {
530             hartid = *(int *)data;
531             __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
532                                                (hartid * 4))) = METAL_ENABLE;
533             __METAL_ACCESS_ONCE((__metal_io_u8 *)(control_base +
534                                                METAL_SIFIVE_CLIC0_MMODE_APERTURE +
535                                                METAL_SIFIVE_CLIC0_CLICINTIP_BASE)) = METAL_ENABLE;
536             rc = 0;
537         }
538         break;
539     case METAL_SOFTWARE_MSIP_GET:
540         rc = 0;
541         if (data) {
542             hartid = *(int *)data;
543             rc = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
544                                                     (hartid * 4)));
545         }
546         break;
547     default:
548         break;
549     }
550
551     return rc;
552 }
553 __METAL_DEFINE_VTABLE(__metal_driver_vtable_sifive_clic0) = {
554     .clic_vtable.interrupt_init     = __metal_driver_sifive_clic0_init,
555     .clic_vtable.interrupt_register = __metal_driver_sifive_clic0_register,
556     .clic_vtable.interrupt_enable   = __metal_driver_sifive_clic0_enable,
557     .clic_vtable.interrupt_disable  = __metal_driver_sifive_clic0_disable,
558     .clic_vtable.interrupt_vector_enable   = __metal_driver_sifive_clic0_enable_interrupt_vector,
559     .clic_vtable.interrupt_vector_disable  = __metal_driver_sifive_clic0_disable_interrupt_vector,
560     .clic_vtable.command_request    = __metal_driver_sifive_clic0_command_request,
561     .clic_vtable.mtimecmp_set       = __metal_driver_sifive_clic0_mtimecmp_set,
562 };
563
564 #endif /* METAL_SIFIVE_CLIC0 */