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