1 /*
2  * Copyright (c) 2016 Cadence Design Systems, Inc.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #ifndef ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_IRQ_H_
7 #define ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_IRQ_H_
8 
9 #include <stdint.h>
10 
11 #include <zephyr/toolchain.h>
12 #include <xtensa/config/core-isa.h>
13 
14 #define CONFIG_GEN_IRQ_START_VECTOR 0
15 
16 /**
17  * @cond INTERNAL_HIDDEN
18  */
19 
20 /*
21  * Call this function to enable the specified interrupts.
22  *
23  * mask     - Bit mask of interrupts to be enabled.
24  */
z_xt_ints_on(unsigned int mask)25 static inline void z_xt_ints_on(unsigned int mask)
26 {
27 	int val;
28 
29 	__asm__ volatile("rsr.intenable %0" : "=r"(val));
30 	val |= mask;
31 	__asm__ volatile("wsr.intenable %0; rsync" : : "r"(val));
32 }
33 
34 
35 /*
36  * Call this function to disable the specified interrupts.
37  *
38  * mask     - Bit mask of interrupts to be disabled.
39  */
z_xt_ints_off(unsigned int mask)40 static inline void z_xt_ints_off(unsigned int mask)
41 {
42 	int val;
43 
44 	__asm__ volatile("rsr.intenable %0" : "=r"(val));
45 	val &= ~mask;
46 	__asm__ volatile("wsr.intenable %0; rsync" : : "r"(val));
47 }
48 
49 
50 /*
51  * Call this function to set the specified (s/w) interrupt.
52  */
z_xt_set_intset(unsigned int arg)53 static inline void z_xt_set_intset(unsigned int arg)
54 {
55 #if XCHAL_HAVE_INTERRUPTS
56 	__asm__ volatile("wsr.intset %0; rsync" : : "r"(arg));
57 #else
58 	ARG_UNUSED(arg);
59 #endif
60 }
61 
62 /**
63  * INTERNAL_HIDDEN @endcond
64  */
65 
66 #ifdef CONFIG_MULTI_LEVEL_INTERRUPTS
67 
68 /* for _soc_irq_*() */
69 #include <soc.h>
70 
71 #ifdef CONFIG_2ND_LEVEL_INTERRUPTS
72 #ifdef CONFIG_3RD_LEVEL_INTERRUPTS
73 #define CONFIG_NUM_IRQS (XCHAL_NUM_INTERRUPTS +\
74 			(CONFIG_NUM_2ND_LEVEL_AGGREGATORS +\
75 			CONFIG_NUM_3RD_LEVEL_AGGREGATORS) *\
76 			CONFIG_MAX_IRQ_PER_AGGREGATOR)
77 #else
78 #define CONFIG_NUM_IRQS (XCHAL_NUM_INTERRUPTS +\
79 			CONFIG_NUM_2ND_LEVEL_AGGREGATORS *\
80 			CONFIG_MAX_IRQ_PER_AGGREGATOR)
81 #endif /* CONFIG_3RD_LEVEL_INTERRUPTS */
82 #else
83 #define CONFIG_NUM_IRQS XCHAL_NUM_INTERRUPTS
84 #endif /* CONFIG_2ND_LEVEL_INTERRUPTS */
85 
86 void z_soc_irq_init(void);
87 void z_soc_irq_enable(unsigned int irq);
88 void z_soc_irq_disable(unsigned int irq);
89 int z_soc_irq_is_enabled(unsigned int irq);
90 
91 #define arch_irq_enable(irq)	z_soc_irq_enable(irq)
92 #define arch_irq_disable(irq)	z_soc_irq_disable(irq)
93 
94 #define arch_irq_is_enabled(irq)	z_soc_irq_is_enabled(irq)
95 
96 #ifdef CONFIG_DYNAMIC_INTERRUPTS
97 extern int z_soc_irq_connect_dynamic(unsigned int irq, unsigned int priority,
98 				     void (*routine)(const void *parameter),
99 				     const void *parameter, uint32_t flags);
100 #endif
101 
102 #else
103 
104 #define CONFIG_NUM_IRQS XCHAL_NUM_INTERRUPTS
105 
106 #define arch_irq_enable(irq)	xtensa_irq_enable(irq)
107 #define arch_irq_disable(irq)	xtensa_irq_disable(irq)
108 
109 #define arch_irq_is_enabled(irq)	xtensa_irq_is_enabled(irq)
110 
111 #endif
112 
113 /**
114  * @brief Enable interrupt on Xtensa core.
115  *
116  * @param irq Interrupt to be enabled.
117  */
xtensa_irq_enable(uint32_t irq)118 static ALWAYS_INLINE void xtensa_irq_enable(uint32_t irq)
119 {
120 	z_xt_ints_on(1 << irq);
121 }
122 
123 /**
124  * @brief Disable interrupt on Xtensa core.
125  *
126  * @param irq Interrupt to be disabled.
127  */
xtensa_irq_disable(uint32_t irq)128 static ALWAYS_INLINE void xtensa_irq_disable(uint32_t irq)
129 {
130 	z_xt_ints_off(1 << irq);
131 }
132 
133 /** Implementation of @ref arch_irq_lock. */
arch_irq_lock(void)134 static ALWAYS_INLINE unsigned int arch_irq_lock(void)
135 {
136 	unsigned int key;
137 
138 	__asm__ volatile("rsil %0, %1"
139 			 : "=r"(key) : "i"(XCHAL_EXCM_LEVEL) : "memory");
140 	return key;
141 }
142 
143 /** Implementation of @ref arch_irq_unlock. */
arch_irq_unlock(unsigned int key)144 static ALWAYS_INLINE void arch_irq_unlock(unsigned int key)
145 {
146 	__asm__ volatile("wsr.ps %0; rsync"
147 			 :: "r"(key) : "memory");
148 }
149 
150 /** Implementation of @ref arch_irq_unlocked. */
arch_irq_unlocked(unsigned int key)151 static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key)
152 {
153 	return (key & 0xf) == 0; /* INTLEVEL field */
154 }
155 
156 /**
157  * @brief Query if an interrupt is enabled on Xtensa core.
158  *
159  * @param irq Interrupt to be queried.
160  *
161  * @return True if interrupt is enabled, false otherwise.
162  */
163 int xtensa_irq_is_enabled(unsigned int irq);
164 
165 #include <zephyr/irq.h>
166 
167 #endif /* ZEPHYR_INCLUDE_ARCH_XTENSA_XTENSA_IRQ_H_ */
168