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