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