]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/src/drivers/riscv_plic0.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 / riscv_plic0.c
1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
3
4 #include <metal/machine/platform.h>
5
6 #ifdef METAL_RISCV_PLIC0
7
8 #include <metal/io.h>
9 #include <metal/shutdown.h>
10 #include <metal/drivers/riscv_plic0.h>
11 #include <metal/machine.h>
12
13 unsigned int __metal_plic0_claim_interrupt (struct __metal_driver_riscv_plic0 *plic)
14 {
15     unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
16     return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
17                                               METAL_RISCV_PLIC0_CLAIM));
18 }
19
20 void __metal_plic0_complete_interrupt(struct __metal_driver_riscv_plic0 *plic,
21                                     unsigned int id)
22 {
23     unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
24     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
25                                        METAL_RISCV_PLIC0_CLAIM)) = id;
26 }
27
28 int __metal_plic0_set_threshold(struct metal_interrupt *controller, unsigned int threshold)
29 {
30     unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
31     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
32                                        METAL_RISCV_PLIC0_THRESHOLD)) = threshold;
33     return 0;
34 }
35
36 unsigned int __metal_plic0_get_threshold(struct metal_interrupt *controller)
37 {
38     unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
39
40     return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
41                                        METAL_RISCV_PLIC0_THRESHOLD));
42 }
43
44 int __metal_plic0_set_priority(struct metal_interrupt *controller, int id, unsigned int priority)
45 {
46     unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)controller);
47     unsigned int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)controller);
48     if ( (max_priority) && (priority < max_priority) ) {
49         __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
50                                            METAL_RISCV_PLIC0_PRIORITY_BASE +
51                                            (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))) = priority;
52         return 0;
53     }
54     return -1;
55 }
56
57 unsigned int __metal_plic0_get_priority(struct metal_interrupt *controller, int id)
58 {
59     unsigned long control_base = __metal_driver_sifive_plic0_control_base(controller);
60
61     return __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
62                                            METAL_RISCV_PLIC0_PRIORITY_BASE +
63                                            (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT)));
64 }
65
66 void __metal_plic0_enable(struct __metal_driver_riscv_plic0 *plic, int id, int enable)
67 {
68     unsigned int current;
69     unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
70
71     current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
72                                                 METAL_RISCV_PLIC0_ENABLE_BASE +
73                                                 (id >> METAL_PLIC_SOURCE_SHIFT) * 4));
74     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
75                                         METAL_RISCV_PLIC0_ENABLE_BASE +
76                                         ((id >> METAL_PLIC_SOURCE_SHIFT) * 4))) =
77               enable ? (current | (1 << (id & METAL_PLIC_SOURCE_MASK)))
78                      : (current & ~(1 << (id & METAL_PLIC_SOURCE_MASK)));
79 }
80
81 void __metal_plic0_default_handler (int id, void *priv) {
82     metal_shutdown(300);
83 }
84
85 void __metal_plic0_handler (int id, void *priv)
86 {
87     struct __metal_driver_riscv_plic0 *plic = priv;
88     unsigned int idx = __metal_plic0_claim_interrupt(plic);
89     unsigned int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic);
90
91     if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) {
92         plic->metal_exint_table[idx](idx,
93                                   plic->metal_exdata_table[idx].exint_data);
94     }
95
96     __metal_plic0_complete_interrupt(plic, idx);
97 }
98
99 void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller)
100 {
101     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
102
103     if ( !plic->init_done ) {
104         int num_interrupts, line;
105         struct metal_interrupt *intc;
106
107         for(int parent = 0; parent < __METAL_PLIC_NUM_PARENTS; parent++) {
108             num_interrupts = __metal_driver_sifive_plic0_num_interrupts(controller);
109             intc = __metal_driver_sifive_plic0_interrupt_parents(controller, parent);
110             line = __metal_driver_sifive_plic0_interrupt_lines(controller, parent);
111
112             /* Initialize ist parent controller, aka cpu_intc. */
113             intc->vtable->interrupt_init(intc);
114
115             for (int i = 0; i < num_interrupts; i++) {
116                 __metal_plic0_enable(plic, i, METAL_DISABLE);
117                 __metal_plic0_set_priority(controller, i, 0);
118                 plic->metal_exint_table[i] = NULL;
119                 plic->metal_exdata_table[i].sub_int = NULL;
120                 plic->metal_exdata_table[i].exint_data = NULL;
121             }
122
123             __metal_plic0_set_threshold(controller, 0);
124
125             /* Register plic (ext) interrupt with with parent controller */
126             intc->vtable->interrupt_register(intc, line, NULL, plic);
127             /* Register plic handler for dispatching its device interrupts */
128             intc->vtable->interrupt_register(intc, line, __metal_plic0_handler, plic);
129             /* Enable plic (ext) interrupt with with parent controller */
130             intc->vtable->interrupt_enable(intc, line);
131         }
132         plic->init_done = 1;
133     }
134 }
135
136 int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller,
137                                        int id, metal_interrupt_handler_t isr,
138                                        void *priv)
139 {
140     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
141
142     if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
143         return -1;
144     }
145  
146     if (isr) {
147         __metal_plic0_set_priority(controller, id, 2);
148         plic->metal_exint_table[id] = isr;
149         plic->metal_exdata_table[id].exint_data = priv;
150     } else {
151         __metal_plic0_set_priority(controller, id, 1);
152         plic->metal_exint_table[id] = __metal_plic0_default_handler;
153         plic->metal_exdata_table[id].sub_int = priv;
154     }
155
156     return 0;
157 }
158
159 int __metal_driver_riscv_plic0_enable (struct metal_interrupt *controller, int id)
160 {
161     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
162
163     if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
164         return -1;
165     }
166
167     __metal_plic0_enable(plic, id, METAL_ENABLE);
168     return 0;
169 }
170
171 int __metal_driver_riscv_plic0_disable (struct metal_interrupt *controller, int id)
172 {
173     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
174
175     if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
176         return -1;
177     }
178     __metal_plic0_enable(plic, id, METAL_DISABLE);
179     return 0;
180 }
181
182 __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = {
183     .plic_vtable.interrupt_init = __metal_driver_riscv_plic0_init,
184     .plic_vtable.interrupt_register = __metal_driver_riscv_plic0_register,
185     .plic_vtable.interrupt_enable   = __metal_driver_riscv_plic0_enable,
186     .plic_vtable.interrupt_disable  = __metal_driver_riscv_plic0_disable,
187     .plic_vtable.interrupt_get_threshold  = __metal_plic0_get_threshold,
188     .plic_vtable.interrupt_set_threshold  = __metal_plic0_set_threshold,
189     .plic_vtable.interrupt_get_priority  = __metal_plic0_get_priority,
190     .plic_vtable.interrupt_set_priority  = __metal_plic0_set_priority,
191 };
192
193 #endif /* METAL_RISCV_PLIC0 */
194
195 typedef int no_empty_translation_units;