1 /* arcv2_irq_unit.h - ARCv2 Interrupt Unit device driver */
2
3 /*
4 * Copyright (c) 2014 Wind River Systems, Inc.
5 * Copyright (c) 2020 Synopsys.
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #ifndef ZEPHYR_INCLUDE_ARCH_ARC_V2_ARCV2_IRQ_UNIT_H_
11 #define ZEPHYR_INCLUDE_ARCH_ARC_V2_ARCV2_IRQ_UNIT_H_
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 /* configuration flags for interrupt unit */
18 #define _ARC_V2_INT_PRIO_MASK 0xf
19 #define _ARC_V2_INT_DISABLE 0
20 #define _ARC_V2_INT_ENABLE 1
21
22 #define _ARC_V2_INT_LEVEL 0
23 #define _ARC_V2_INT_PULSE 1
24
25 #ifndef _ASMLANGUAGE
26
27 /*
28 * NOTE:
29 *
30 * All APIs provided by this file are protected with INTERRUPTS LOCKED. The
31 * APIs themselves are writing the IRQ_SELECT, selecting which IRQ's registers
32 * it wants to write to, then write to them: THIS IS NOT AN ATOMIC OPERATION.
33 *
34 * Locking the interrupts inside of the APIs are some kind of self-protection
35 * to guarantee the correctness of operation if the callers don't lock
36 * the interrupt.
37 *
38 */
39
40 /**
41 * @brief Enable/disable interrupt
42 *
43 * Enables or disables the specified interrupt
44 */
45
46 static ALWAYS_INLINE
z_arc_v2_irq_unit_irq_enable_set(int irq,unsigned char enable)47 void z_arc_v2_irq_unit_irq_enable_set(
48 int irq,
49 unsigned char enable
50 )
51 {
52 unsigned int key = arch_irq_lock();
53
54 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
55 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_ENABLE, enable);
56
57 arch_irq_unlock(key);
58 }
59
60 /**
61 * @brief Enable interrupt
62 *
63 * Enables the specified interrupt
64 */
65
66 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_enable(int irq)67 void z_arc_v2_irq_unit_int_enable(int irq)
68 {
69 z_arc_v2_irq_unit_irq_enable_set(irq, _ARC_V2_INT_ENABLE);
70 }
71
72 /**
73 * @brief Disable interrupt
74 *
75 * Disables the specified interrupt
76 */
77
78 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_disable(int irq)79 void z_arc_v2_irq_unit_int_disable(int irq)
80 {
81 z_arc_v2_irq_unit_irq_enable_set(irq, _ARC_V2_INT_DISABLE);
82 }
83
84 /**
85 * @brief Poll the enable status of interrupt
86 *
87 * Polls the enable status of the specified interrupt
88 *
89 * @return 1 enabled, 0 disabled
90 */
91
92 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_enabled(int irq)93 bool z_arc_v2_irq_unit_int_enabled(int irq)
94 {
95 bool ret;
96 unsigned int key = arch_irq_lock();
97
98 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
99 ret = z_arc_v2_aux_reg_read(_ARC_V2_IRQ_ENABLE) & 0x1;
100
101 arch_irq_unlock(key);
102
103 return ret;
104 }
105
106
107 /**
108 * @brief Set interrupt priority
109 *
110 * Set the priority of the specified interrupt
111 */
112
113 static ALWAYS_INLINE
z_arc_v2_irq_unit_prio_set(int irq,unsigned char prio)114 void z_arc_v2_irq_unit_prio_set(int irq, unsigned char prio)
115 {
116
117 unsigned int key = arch_irq_lock();
118
119 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
120 #if defined(CONFIG_ARC_SECURE_FIRMWARE)
121 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY,
122 (z_arc_v2_aux_reg_read(_ARC_V2_IRQ_PRIORITY) & (~_ARC_V2_INT_PRIO_MASK))
123 | prio);
124 #else
125 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY, prio);
126 #endif
127 arch_irq_unlock(key);
128 }
129
130 #if defined(CONFIG_ARC_SECURE_FIRMWARE)
131 /**
132 * @brief Configure the secure state of interrupt
133 *
134 * Configure the secure state of the specified interrupt
135 */
136 static ALWAYS_INLINE
z_arc_v2_irq_uinit_secure_set(int irq,bool secure)137 void z_arc_v2_irq_uinit_secure_set(int irq, bool secure)
138 {
139 unsigned int key = arch_irq_lock();
140
141 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
142
143 if (secure) {
144 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY,
145 z_arc_v2_aux_reg_read(_ARC_V2_IRQ_PRIORITY) |
146 _ARC_V2_IRQ_PRIORITY_SECURE);
147 } else {
148 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY,
149 z_arc_v2_aux_reg_read(_ARC_V2_IRQ_PRIORITY) &
150 _ARC_V2_INT_PRIO_MASK);
151 }
152
153 arch_irq_unlock(key);
154 }
155 #endif
156
157 /**
158 * @brief Set interrupt sensitivity
159 *
160 * Set the sensitivity of the specified interrupt to either
161 * _ARC_V2_INT_LEVEL or _ARC_V2_INT_PULSE. Level interrupts will remain
162 * asserted until the interrupt handler clears the interrupt at the peripheral.
163 * Pulse interrupts self-clear as the interrupt handler is entered.
164 */
165
166 static ALWAYS_INLINE
z_arc_v2_irq_unit_sensitivity_set(int irq,int s)167 void z_arc_v2_irq_unit_sensitivity_set(int irq, int s)
168 {
169 unsigned int key = arch_irq_lock();
170
171 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
172 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_TRIGGER, s);
173
174 arch_irq_unlock(key);
175 }
176
177 /*
178 * @brief Check whether processor in interrupt/exception state
179 *
180 * Check whether processor in interrupt/exception state
181 *
182 * @return 1 in interrupt/exception state; 0 not in
183 */
184 static ALWAYS_INLINE
z_arc_v2_irq_unit_is_in_isr(void)185 bool z_arc_v2_irq_unit_is_in_isr(void)
186 {
187 uint32_t act = z_arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_ACT);
188
189 /* in exception ?*/
190 if (z_arc_v2_aux_reg_read(_ARC_V2_STATUS32) & _ARC_V2_STATUS32_AE) {
191 return true;
192 }
193
194 return ((act & 0xffff) != 0U);
195 }
196
197 /**
198 * @brief Sets an IRQ line to level/pulse trigger
199 *
200 * Sets the IRQ line <irq> to trigger an interrupt based on the level or the
201 * edge of the signal. Valid values for <trigger> are _ARC_V2_INT_LEVEL and
202 * _ARC_V2_INT_PULSE.
203 */
204 static ALWAYS_INLINE
z_arc_v2_irq_unit_trigger_set(int irq,unsigned int trigger)205 void z_arc_v2_irq_unit_trigger_set(int irq, unsigned int trigger)
206 {
207 unsigned int key = arch_irq_lock();
208
209 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
210 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_TRIGGER, trigger);
211
212 arch_irq_unlock(key);
213 }
214
215 /**
216 * @brief Returns an IRQ line trigger type
217 *
218 * Gets the IRQ line <irq> trigger type.
219 * Valid values for <trigger> are _ARC_V2_INT_LEVEL and _ARC_V2_INT_PULSE.
220 *
221 * @return trigger state
222 */
223 static ALWAYS_INLINE
z_arc_v2_irq_unit_trigger_get(int irq)224 unsigned int z_arc_v2_irq_unit_trigger_get(int irq)
225 {
226 unsigned int ret;
227 unsigned int key = arch_irq_lock();
228
229 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
230 ret = z_arc_v2_aux_reg_read(_ARC_V2_IRQ_TRIGGER);
231
232 arch_irq_unlock(key);
233
234 return ret;
235 }
236
237 /**
238 * @brief Send EOI signal to interrupt unit
239 *
240 * This routine sends an EOI (End Of Interrupt) signal to the interrupt unit
241 * to clear a pulse-triggered interrupt.
242 */
243 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_eoi(int irq)244 void z_arc_v2_irq_unit_int_eoi(int irq)
245 {
246 unsigned int key = arch_irq_lock();
247
248 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
249 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PULSE_CANCEL, 1);
250
251 arch_irq_unlock(key);
252 }
253
254 #endif /* _ASMLANGUAGE */
255
256 #ifdef __cplusplus
257 }
258 #endif
259
260 #endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_ARCV2_IRQ_UNIT_H_ */
261