]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_IAR/SiFive_code/riscv_plic0.c
Minor updates to comment block for xTaskCheckForTimeOut().
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_IAR / SiFive_code / 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 void __metal_plic0_set_threshold(struct __metal_driver_riscv_plic0 *plic,
29                                unsigned int threshold)
30 {
31     unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
32     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
33                                        METAL_RISCV_PLIC0_THRESHOLD)) = threshold;
34 }
35
36 void __metal_plic0_set_priority(struct __metal_driver_riscv_plic0 *plic,
37                               int id, unsigned int priority)
38 {
39     unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
40     int max_priority = __metal_driver_sifive_plic0_max_priority((struct metal_interrupt *)plic);
41     if ( (max_priority) && (priority < max_priority) ) {
42         __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
43                                            METAL_RISCV_PLIC0_PRIORITY_BASE +
44                                            (id << METAL_PLIC_SOURCE_PRIORITY_SHIFT))) = priority;
45     }
46 }
47
48 void __metal_plic0_enable(struct __metal_driver_riscv_plic0 *plic, int id, int enable)
49 {
50     unsigned int current;
51     unsigned long hartid = __metal_myhart_id();
52     unsigned long control_base = __metal_driver_sifive_plic0_control_base((struct metal_interrupt *)plic);
53
54     current = __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
55                                                 METAL_RISCV_PLIC0_ENABLE_BASE +
56                                                 (id >> METAL_PLIC_SOURCE_SHIFT) * 4));
57     __METAL_ACCESS_ONCE((__metal_io_u32 *)(control_base +
58                                         METAL_RISCV_PLIC0_ENABLE_BASE +
59                                         ((id >> METAL_PLIC_SOURCE_SHIFT) * 4))) =
60               enable ? (current | (1 << (id & METAL_PLIC_SOURCE_MASK)))
61                      : (current & ~(1 << (id & METAL_PLIC_SOURCE_MASK)));
62 }
63
64 void __metal_plic0_default_handler (int id, void *priv) {
65     metal_shutdown(300);
66 }
67
68 void __metal_plic0_handler (int id, void *priv)
69 {
70     struct __metal_driver_riscv_plic0 *plic = priv;
71     unsigned int idx = __metal_plic0_claim_interrupt(plic);
72     int num_interrupts = __metal_driver_sifive_plic0_num_interrupts((struct metal_interrupt *)plic);
73
74     if ( (idx < num_interrupts) && (plic->metal_exint_table[idx]) ) {
75         plic->metal_exint_table[idx](idx,
76                                   plic->metal_exdata_table[idx].exint_data);
77     }
78
79     __metal_plic0_complete_interrupt(plic, idx);
80 }
81
82 void __metal_driver_riscv_plic0_init (struct metal_interrupt *controller)
83 {
84     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
85
86     if ( !plic->init_done ) {
87         int num_interrupts, line;
88         struct metal_interrupt *intc;
89
90         for(int parent = 0; parent < __METAL_PLIC_NUM_PARENTS; parent++) {
91             num_interrupts = __metal_driver_sifive_plic0_num_interrupts(controller);
92             intc = __metal_driver_sifive_plic0_interrupt_parents(controller, parent);
93             line = __metal_driver_sifive_plic0_interrupt_lines(controller, parent);
94
95             /* Initialize ist parent controller, aka cpu_intc. */
96             intc->vtable->interrupt_init(intc);
97
98             for (int i = 0; i < num_interrupts; i++) {
99                 __metal_plic0_enable(plic, i, METAL_DISABLE);
100                 __metal_plic0_set_priority(plic, i, 0);
101                 plic->metal_exint_table[i] = NULL;
102                 plic->metal_exdata_table[i].sub_int = NULL;
103                 plic->metal_exdata_table[i].exint_data = NULL;
104             }
105
106             __metal_plic0_set_threshold(plic, 0);
107
108             /* Register plic (ext) interrupt with with parent controller */
109             intc->vtable->interrupt_register(intc, line, NULL, plic);
110             /* Register plic handler for dispatching its device interrupts */
111             intc->vtable->interrupt_register(intc, line, __metal_plic0_handler, plic);
112             /* Enable plic (ext) interrupt with with parent controller */
113             intc->vtable->interrupt_enable(intc, line);
114         }
115         plic->init_done = 1;
116     }
117 }
118
119 int __metal_driver_riscv_plic0_register (struct metal_interrupt *controller,
120                                        int id, metal_interrupt_handler_t isr,
121                                        void *priv)
122 {
123     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
124
125     if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
126         return -1;
127     }
128  
129     if (isr) {
130         __metal_plic0_set_priority(plic ,id, 2);
131         plic->metal_exint_table[id] = isr;
132         plic->metal_exdata_table[id].exint_data = priv;
133     } else {
134         __metal_plic0_set_priority(plic, id, 1);
135         plic->metal_exint_table[id] = __metal_plic0_default_handler;
136         plic->metal_exdata_table[id].sub_int = priv;
137     }
138
139     return 0;
140 }
141
142 int __metal_driver_riscv_plic0_enable (struct metal_interrupt *controller, int id)
143 {
144     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
145
146     if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
147         return -1;
148     }
149
150     __metal_plic0_enable(plic, id, METAL_ENABLE);
151     return 0;
152 }
153
154 int __metal_driver_riscv_plic0_disable (struct metal_interrupt *controller, int id)
155 {
156     struct __metal_driver_riscv_plic0 *plic = (void *)(controller);
157
158     if (id >= __metal_driver_sifive_plic0_num_interrupts(controller)) {
159         return -1;
160     }
161     __metal_plic0_enable(plic, id, METAL_DISABLE);
162     return 0;
163 }
164
165 __METAL_DEFINE_VTABLE(__metal_driver_vtable_riscv_plic0) = {
166     .plic_vtable.interrupt_init = __metal_driver_riscv_plic0_init,
167     .plic_vtable.interrupt_register = __metal_driver_riscv_plic0_register,
168     .plic_vtable.interrupt_enable   = __metal_driver_riscv_plic0_enable,
169     .plic_vtable.interrupt_disable  = __metal_driver_riscv_plic0_disable,
170 };
171
172 #endif /* METAL_RISCV_PLIC0 */