1 /*
2 * Copyright (c) 2021 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 /* Enable Register - 0x80 per target */
34 #define HPM_PLIC_ENABLE_OFFSET (0x00002000UL)
35 #define HPM_PLIC_ENABLE_SHIFT_PER_TARGET 7
36
37 /* Priority Threshold Register - 0x1000 per target */
38 #define HPM_PLIC_THRESHOLD_OFFSET (0x00200000UL)
39 #define HPM_PLIC_THRESHOLD_SHIFT_PER_TARGET 12
40
41 /* Claim Register - 0x1000 per target */
42 #define HPM_PLIC_CLAIM_OFFSET (0x00200004UL)
43 #define HPM_PLIC_CLAIM_SHIFT_PER_TARGET 12
44
45 #if !defined(__ASSEMBLER__)
46
47 /**
48 * @brief Set plic feature
49 *
50 * @param[in] base PLIC base address
51 * @param[in] feature Specific feature to be set
52 *
53 */
__plic_set_feature(uint32_t base,uint32_t feature)54 ATTR_ALWAYS_INLINE static inline void __plic_set_feature(uint32_t base, uint32_t feature)
55 {
56 *(volatile uint32_t *)(base + HPM_PLIC_FEATURE_OFFSET) = feature;
57 }
58
59 /**
60 * @brief Set plic threshold
61 *
62 * @param[in] base PLIC base address
63 * @param[in] target Target to handle specific interrupt
64 * @param[in] threshold Threshold of IRQ can be serviced
65 *
66 */
__plic_set_threshold(uint32_t base,uint32_t target,uint32_t threshold)67 ATTR_ALWAYS_INLINE static inline void __plic_set_threshold(uint32_t base,
68 uint32_t target,
69 uint32_t threshold)
70 {
71 volatile uint32_t *threshold_ptr = (volatile uint32_t *)(base +
72 HPM_PLIC_THRESHOLD_OFFSET +
73 (target << HPM_PLIC_THRESHOLD_SHIFT_PER_TARGET));
74 *threshold_ptr = threshold;
75 }
76
77 /**
78 * @brief Set interrupt priority
79 *
80 * @param[in] base PLIC base address
81 * @param[in] irq Target interrupt number
82 * @param[in] priority Priority to be assigned
83 *
84 */
__plic_set_irq_priority(uint32_t base,uint32_t irq,uint32_t priority)85 ATTR_ALWAYS_INLINE static inline void __plic_set_irq_priority(uint32_t base,
86 uint32_t irq,
87 uint32_t priority)
88 {
89 volatile uint32_t *priority_ptr = (volatile uint32_t *)(base +
90 HPM_PLIC_PRIORITY_OFFSET + ((irq-1) << HPM_PLIC_PRIORITY_SHIFT_PER_SOURCE));
91 *priority_ptr = priority;
92 }
93
94 /**
95 * @brief Set interrupt pending bit
96 *
97 * @param[in] base PLIC base address
98 * @param[in] irq Target interrupt number
99 *
100 */
__plic_set_irq_pending(uint32_t base,uint32_t irq)101 ATTR_ALWAYS_INLINE static inline void __plic_set_irq_pending(uint32_t base, uint32_t irq)
102 {
103 volatile uint32_t *current_ptr = (volatile uint32_t *)(base +
104 HPM_PLIC_PENDING_OFFSET + ((irq >> 5) << 2));
105 *current_ptr = (1 << (irq & 0x1F));
106 }
107
108 /**
109 * @brief Enable interrupt
110 *
111 * @param[in] base PLIC base address
112 * @param[in] target Target to handle specific interrupt
113 * @param[in] irq Interrupt number to be enabled
114 *
115 */
__plic_enable_irq(uint32_t base,uint32_t target,uint32_t irq)116 ATTR_ALWAYS_INLINE static inline void __plic_enable_irq(uint32_t base,
117 uint32_t target,
118 uint32_t irq)
119 {
120 volatile uint32_t *current_ptr = (volatile uint32_t *)(base +
121 HPM_PLIC_ENABLE_OFFSET +
122 (target << HPM_PLIC_ENABLE_SHIFT_PER_TARGET) +
123 ((irq >> 5) << 2));
124 uint32_t current = *current_ptr;
125 current = current | (1 << (irq & 0x1F));
126 *current_ptr = current;
127 }
128
129 /**
130 * @brief Disable interrupt
131 *
132 * @param[in] base PLIC base address
133 * @param[in] target Target to handle specific interrupt
134 * @param[in] irq Interrupt number to be disabled
135 *
136 */
__plic_disable_irq(uint32_t base,uint32_t target,uint32_t irq)137 ATTR_ALWAYS_INLINE static inline void __plic_disable_irq(uint32_t base,
138 uint32_t target,
139 uint32_t irq)
140 {
141 volatile uint32_t *current_ptr = (volatile uint32_t *)(base +
142 HPM_PLIC_ENABLE_OFFSET +
143 (target << HPM_PLIC_ENABLE_SHIFT_PER_TARGET) +
144 ((irq >> 5) << 2));
145 uint32_t current = *current_ptr;
146 current = current & ~((1 << (irq & 0x1F)));
147 *current_ptr = current;
148 }
149
150 /**
151 * @brief Claim interrupt
152 *
153 * @param[in] base PLIC base address
154 * @param[in] target Target to claim interrupt
155 *
156 */
__plic_claim_irq(uint32_t base,uint32_t target)157 ATTR_ALWAYS_INLINE static inline uint32_t __plic_claim_irq(uint32_t base, uint32_t target)
158 {
159 volatile uint32_t *claim_addr = (volatile uint32_t *)(base +
160 HPM_PLIC_CLAIM_OFFSET +
161 (target << HPM_PLIC_CLAIM_SHIFT_PER_TARGET));
162 return *claim_addr;
163 }
164
165 /**
166 * @brief Complete interrupt
167 *
168 * @param[in] base PLIC base address
169 * @param[in] target Target to handle specific interrupt
170 * @param[in] irq Interrupt number
171 *
172 */
__plic_complete_irq(uint32_t base,uint32_t target,uint32_t irq)173 ATTR_ALWAYS_INLINE static inline void __plic_complete_irq(uint32_t base,
174 uint32_t target,
175 uint32_t irq)
176 {
177 volatile uint32_t *claim_addr = (volatile uint32_t *)(base +
178 HPM_PLIC_CLAIM_OFFSET +
179 (target << HPM_PLIC_CLAIM_SHIFT_PER_TARGET));
180 *claim_addr = irq;
181 }
182 #endif /* __ASSEMBLER__ */
183 /**
184 * @}
185 */
186 #endif /* HPM_PLIC_DRV_H */
187