1 /*
2 * Copyright (c) 2021-2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #ifndef HPM_PLIC_DRV_H
9 #define HPM_PLIC_DRV_H
10
11 /**
12 * @brief PLIC driver APIs
13 * @defgroup plic_interface PLIC driver APIs
14 * @{
15 */
16
17 #define HPM_PLIC_TARGET_M_MODE 0
18 #define HPM_PLIC_TARGET_S_MODE 1
19
20 /* Feature Register */
21 #define HPM_PLIC_FEATURE_OFFSET (0x00000000UL)
22 #define HPM_PLIC_FEATURE_VECTORED_MODE (0x2UL)
23 #define HPM_PLIC_FEATURE_PREEMPTIVE_PRIORITY_IRQ (0x1UL)
24
25 /* Priority Register - 32 bits per irq */
26 #define HPM_PLIC_PRIORITY_OFFSET (0x00000004UL)
27 #define HPM_PLIC_PRIORITY_SHIFT_PER_SOURCE 2
28
29 /* Pending Register - 1 bit per source */
30 #define HPM_PLIC_PENDING_OFFSET (0x00001000UL)
31 #define HPM_PLIC_PENDING_SHIFT_PER_SOURCE 0
32
33 #define HPM_PLIC_TRIGGER_TYPE_OFFSET (0x00001080UL)
34 #define HPM_PLIC_TRIGGER_TYPE_SHIFT_PER_SORUCE 1
35
36 /* Enable Register - 0x80 per target */
37 #define HPM_PLIC_ENABLE_OFFSET (0x00002000UL)
38 #define HPM_PLIC_ENABLE_SHIFT_PER_TARGET 7
39
40 /* Priority Threshold Register - 0x1000 per target */
41 #define HPM_PLIC_THRESHOLD_OFFSET (0x00200000UL)
42 #define HPM_PLIC_THRESHOLD_SHIFT_PER_TARGET 12
43
44
45 /* Claim Register - 0x1000 per target */
46 #define HPM_PLIC_CLAIM_OFFSET (0x00200004UL)
47 #define HPM_PLIC_CLAIM_SHIFT_PER_TARGET 12
48
49 #if !defined(__ASSEMBLER__)
50
51 /**
52 * @brief Set plic feature
53 *
54 * @param[in] base PLIC base address
55 * @param[in] feature Specific feature to be set
56 *
57 */
__plic_set_feature(uint32_t base,uint32_t feature)58 ATTR_ALWAYS_INLINE static inline void __plic_set_feature(uint32_t base, uint32_t feature)
59 {
60 *(volatile uint32_t *) (base + HPM_PLIC_FEATURE_OFFSET) = feature;
61 }
62
63 /**
64 * @brief Set plic threshold
65 *
66 * @param[in] base PLIC base address
67 * @param[in] target Target to handle specific interrupt
68 * @param[in] threshold Threshold of IRQ can be serviced
69 *
70 */
__plic_set_threshold(uint32_t base,uint32_t target,uint32_t threshold)71 ATTR_ALWAYS_INLINE static inline void __plic_set_threshold(uint32_t base,
72 uint32_t target,
73 uint32_t threshold)
74 {
75 volatile uint32_t *threshold_ptr = (volatile uint32_t *) (base +
76 HPM_PLIC_THRESHOLD_OFFSET +
77 (target << HPM_PLIC_THRESHOLD_SHIFT_PER_TARGET));
78 *threshold_ptr = threshold;
79 }
80
81 /**
82 * @brief Set interrupt priority
83 *
84 * @param[in] base PLIC base address
85 * @param[in] irq Target interrupt number
86 * @param[in] priority Priority to be assigned
87 *
88 */
__plic_set_irq_priority(uint32_t base,uint32_t irq,uint32_t priority)89 ATTR_ALWAYS_INLINE static inline void __plic_set_irq_priority(uint32_t base,
90 uint32_t irq,
91 uint32_t priority)
92 {
93 volatile uint32_t *priority_ptr = (volatile uint32_t *) (base +
94 HPM_PLIC_PRIORITY_OFFSET +
95 ((irq - 1) << HPM_PLIC_PRIORITY_SHIFT_PER_SOURCE));
96 *priority_ptr = priority;
97 }
98
99 /**
100 * @brief Set interrupt pending bit
101 *
102 * @param[in] base PLIC base address
103 * @param[in] irq Target interrupt number
104 *
105 */
__plic_set_irq_pending(uint32_t base,uint32_t irq)106 ATTR_ALWAYS_INLINE static inline void __plic_set_irq_pending(uint32_t base, uint32_t irq)
107 {
108 volatile uint32_t *current_ptr = (volatile uint32_t *) (base +
109 HPM_PLIC_PENDING_OFFSET + ((irq >> 5) << 2));
110 *current_ptr = (1 << (irq & 0x1F));
111 }
112
113 /**
114 * @brief Set interrupt trigger type to edge-triggerred
115 *
116 * @param[in] base PLIC base address
117 * @param[in] irq Target interrupt number
118 *
119 */
__plic_enable_irq_edge_trigger(uint32_t base,uint32_t irq)120 ATTR_ALWAYS_INLINE static inline void __plic_enable_irq_edge_trigger(uint32_t base, uint32_t irq)
121 {
122 volatile uint32_t *current_ptr = (volatile uint32_t *) (base +
123 HPM_PLIC_TRIGGER_TYPE_OFFSET + ((irq >> 5) << 2));
124 *current_ptr |= (1UL << (irq & 0x1F));
125 }
126
127 /**
128 * @brief Set interrupt trigger type to level-triggerred
129 *
130 * @param[in] base PLIC base address
131 * @param[in] irq Target interrupt number
132 *
133 */
__plic_enable_irq_level_trigger(uint32_t base,uint32_t irq)134 ATTR_ALWAYS_INLINE static inline void __plic_enable_irq_level_trigger(uint32_t base, uint32_t irq)
135 {
136 volatile uint32_t *current_ptr = (volatile uint32_t *) (base +
137 HPM_PLIC_TRIGGER_TYPE_OFFSET + ((irq >> 5) << 2));
138 *current_ptr &= ~(1UL << (irq & 0x1F));
139 }
140
141 /**
142 * @brief Enable interrupt
143 *
144 * @param[in] base PLIC base address
145 * @param[in] target Target to handle specific interrupt
146 * @param[in] irq Interrupt number to be enabled
147 *
148 */
__plic_enable_irq(uint32_t base,uint32_t target,uint32_t irq)149 ATTR_ALWAYS_INLINE static inline void __plic_enable_irq(uint32_t base,
150 uint32_t target,
151 uint32_t irq)
152 {
153 volatile uint32_t *current_ptr = (volatile uint32_t *) (base +
154 HPM_PLIC_ENABLE_OFFSET +
155 (target << HPM_PLIC_ENABLE_SHIFT_PER_TARGET) +
156 ((irq >> 5) << 2));
157 uint32_t current = *current_ptr;
158 current = current | (1 << (irq & 0x1F));
159 *current_ptr = current;
160 }
161
162 /**
163 * @brief Disable interrupt
164 *
165 * @param[in] base PLIC base address
166 * @param[in] target Target to handle specific interrupt
167 * @param[in] irq Interrupt number to be disabled
168 *
169 */
__plic_disable_irq(uint32_t base,uint32_t target,uint32_t irq)170 ATTR_ALWAYS_INLINE static inline void __plic_disable_irq(uint32_t base,
171 uint32_t target,
172 uint32_t irq)
173 {
174 volatile uint32_t *current_ptr = (volatile uint32_t *) (base +
175 HPM_PLIC_ENABLE_OFFSET +
176 (target << HPM_PLIC_ENABLE_SHIFT_PER_TARGET) +
177 ((irq >> 5) << 2));
178 uint32_t current = *current_ptr;
179 current = current & ~((1 << (irq & 0x1F)));
180 *current_ptr = current;
181 }
182
183 /**
184 * @brief Claim interrupt
185 *
186 * @param[in] base PLIC base address
187 * @param[in] target Target to claim interrupt
188 *
189 */
__plic_claim_irq(uint32_t base,uint32_t target)190 ATTR_ALWAYS_INLINE static inline uint32_t __plic_claim_irq(uint32_t base, uint32_t target)
191 {
192 volatile uint32_t *claim_addr = (volatile uint32_t *) (base +
193 HPM_PLIC_CLAIM_OFFSET +
194 (target << HPM_PLIC_CLAIM_SHIFT_PER_TARGET));
195 return *claim_addr;
196 }
197
198 /**
199 * @brief Complete interrupt
200 *
201 * @param[in] base PLIC base address
202 * @param[in] target Target to handle specific interrupt
203 * @param[in] irq Interrupt number
204 *
205 */
__plic_complete_irq(uint32_t base,uint32_t target,uint32_t irq)206 ATTR_ALWAYS_INLINE static inline void __plic_complete_irq(uint32_t base,
207 uint32_t target,
208 uint32_t irq)
209 {
210 volatile uint32_t *claim_addr = (volatile uint32_t *) (base +
211 HPM_PLIC_CLAIM_OFFSET +
212 (target << HPM_PLIC_CLAIM_SHIFT_PER_TARGET));
213 *claim_addr = irq;
214 }
215
216 #endif /* __ASSEMBLER__ */
217 /**
218 * @}
219 */
220 #endif /* HPM_PLIC_DRV_H */
221