• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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