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 * @param irq IRQ line number
45 * @param enable 1 to enable, 0 to disable
46 */
47
48 static ALWAYS_INLINE
z_arc_v2_irq_unit_irq_enable_set(int irq,unsigned char enable)49 void z_arc_v2_irq_unit_irq_enable_set(
50 int irq,
51 unsigned char enable
52 )
53 {
54 unsigned int key = arch_irq_lock();
55
56 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
57 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_ENABLE, enable);
58
59 arch_irq_unlock(key);
60 }
61
62 /**
63 * @brief Enable interrupt
64 *
65 * Enables the specified interrupt
66 */
67
68 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_enable(int irq)69 void z_arc_v2_irq_unit_int_enable(int irq)
70 {
71 z_arc_v2_irq_unit_irq_enable_set(irq, _ARC_V2_INT_ENABLE);
72 }
73
74 /**
75 * @brief Disable interrupt
76 *
77 * Disables the specified interrupt
78 */
79
80 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_disable(int irq)81 void z_arc_v2_irq_unit_int_disable(int irq)
82 {
83 z_arc_v2_irq_unit_irq_enable_set(irq, _ARC_V2_INT_DISABLE);
84 }
85
86 /**
87 * @brief Poll the enable status of interrupt
88 *
89 * Polls the enable status of the specified interrupt
90 *
91 * @return 1 enabled, 0 disabled
92 */
93
94 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_enabled(int irq)95 bool z_arc_v2_irq_unit_int_enabled(int irq)
96 {
97 bool ret;
98 unsigned int key = arch_irq_lock();
99
100 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
101 ret = z_arc_v2_aux_reg_read(_ARC_V2_IRQ_ENABLE) & 0x1;
102
103 arch_irq_unlock(key);
104
105 return ret;
106 }
107
108
109 /**
110 * @brief Set interrupt priority
111 *
112 * Set the priority of the specified interrupt
113 */
114
115 static ALWAYS_INLINE
z_arc_v2_irq_unit_prio_set(int irq,unsigned char prio)116 void z_arc_v2_irq_unit_prio_set(int irq, unsigned char prio)
117 {
118
119 unsigned int key = arch_irq_lock();
120
121 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
122 #if defined(CONFIG_ARC_SECURE_FIRMWARE)
123 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY,
124 (z_arc_v2_aux_reg_read(_ARC_V2_IRQ_PRIORITY) & (~_ARC_V2_INT_PRIO_MASK))
125 | prio);
126 #else
127 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY, prio);
128 #endif
129 arch_irq_unlock(key);
130 }
131
132 #if defined(CONFIG_ARC_SECURE_FIRMWARE)
133 /**
134 * @brief Configure the secure state of interrupt
135 *
136 * Configure the secure state of the specified interrupt
137 */
138 static ALWAYS_INLINE
z_arc_v2_irq_uinit_secure_set(int irq,bool secure)139 void z_arc_v2_irq_uinit_secure_set(int irq, bool secure)
140 {
141 unsigned int key = arch_irq_lock();
142
143 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
144
145 if (secure) {
146 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY,
147 z_arc_v2_aux_reg_read(_ARC_V2_IRQ_PRIORITY) |
148 _ARC_V2_IRQ_PRIORITY_SECURE);
149 } else {
150 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PRIORITY,
151 z_arc_v2_aux_reg_read(_ARC_V2_IRQ_PRIORITY) &
152 _ARC_V2_INT_PRIO_MASK);
153 }
154
155 arch_irq_unlock(key);
156 }
157 #endif
158
159 /**
160 * @brief Set interrupt sensitivity
161 *
162 * Set the sensitivity of the specified interrupt to either
163 * _ARC_V2_INT_LEVEL or _ARC_V2_INT_PULSE. Level interrupts will remain
164 * asserted until the interrupt handler clears the interrupt at the peripheral.
165 * Pulse interrupts self-clear as the interrupt handler is entered.
166 */
167
168 static ALWAYS_INLINE
z_arc_v2_irq_unit_sensitivity_set(int irq,int s)169 void z_arc_v2_irq_unit_sensitivity_set(int irq, int s)
170 {
171 unsigned int key = arch_irq_lock();
172
173 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
174 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_TRIGGER, s);
175
176 arch_irq_unlock(key);
177 }
178
179 /*
180 * @brief Check whether processor in interrupt/exception state
181 *
182 * Check whether processor in interrupt/exception state
183 *
184 * @return 1 in interrupt/exception state; 0 not in
185 */
186 static ALWAYS_INLINE
z_arc_v2_irq_unit_is_in_isr(void)187 bool z_arc_v2_irq_unit_is_in_isr(void)
188 {
189 uint32_t act = z_arc_v2_aux_reg_read(_ARC_V2_AUX_IRQ_ACT);
190
191 /* in exception ?*/
192 if (z_arc_v2_aux_reg_read(_ARC_V2_STATUS32) & _ARC_V2_STATUS32_AE) {
193 return true;
194 }
195
196 return ((act & 0xffff) != 0U);
197 }
198
199 /**
200 * @brief Sets an IRQ line to level/pulse trigger
201 *
202 * Sets the IRQ line @p irq to trigger an interrupt based on the level or the
203 * edge of the signal. Valid values for @p trigger are _ARC_V2_INT_LEVEL and
204 * _ARC_V2_INT_PULSE.
205 * @param irq IRQ line
206 * @param trigger Trigger state
207 */
208 static ALWAYS_INLINE
z_arc_v2_irq_unit_trigger_set(int irq,unsigned int trigger)209 void z_arc_v2_irq_unit_trigger_set(int irq, unsigned int trigger)
210 {
211 unsigned int key = arch_irq_lock();
212
213 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
214 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_TRIGGER, trigger);
215
216 arch_irq_unlock(key);
217 }
218
219 /**
220 * @brief Returns an IRQ line trigger type
221 *
222 * Gets the IRQ line @p irq trigger type.
223 * Valid values for @retval trigger are _ARC_V2_INT_LEVEL and _ARC_V2_INT_PULSE.
224 *
225 * @param irq IRQ line
226 *
227 * @return trigger state
228 */
229 static ALWAYS_INLINE
z_arc_v2_irq_unit_trigger_get(int irq)230 unsigned int z_arc_v2_irq_unit_trigger_get(int irq)
231 {
232 unsigned int ret;
233 unsigned int key = arch_irq_lock();
234
235 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
236 ret = z_arc_v2_aux_reg_read(_ARC_V2_IRQ_TRIGGER);
237
238 arch_irq_unlock(key);
239
240 return ret;
241 }
242
243 /**
244 * @brief Send EOI signal to interrupt unit
245 *
246 * This routine sends an EOI (End Of Interrupt) signal to the interrupt unit
247 * to clear a pulse-triggered interrupt.
248 */
249 static ALWAYS_INLINE
z_arc_v2_irq_unit_int_eoi(int irq)250 void z_arc_v2_irq_unit_int_eoi(int irq)
251 {
252 unsigned int key = arch_irq_lock();
253
254 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_SELECT, irq);
255 z_arc_v2_aux_reg_write(_ARC_V2_IRQ_PULSE_CANCEL, 1);
256
257 arch_irq_unlock(key);
258 }
259
260 #endif /* _ASMLANGUAGE */
261
262 #ifdef __cplusplus
263 }
264 #endif
265
266 #endif /* ZEPHYR_INCLUDE_ARCH_ARC_V2_ARCV2_IRQ_UNIT_H_ */
267