1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2018 Intel Corporation. All rights reserved.
4  *
5  * Author: Janusz Jankowski <janusz.jankowski@linux.intel.com>
6  */
7 
8 #ifndef __SOF_DRIVERS_INTERRUPT_H__
9 #define __SOF_DRIVERS_INTERRUPT_H__
10 
11 #include <platform/drivers/interrupt.h>
12 
13 #if !defined(__ASSEMBLER__) && !defined(LINKER)
14 #include <arch/drivers/interrupt.h>
15 #include <sof/lib/cpu.h>
16 #include <sof/list.h>
17 #include <sof/sof.h>
18 #include <sof/spinlock.h>
19 #include <sof/trace/trace.h>
20 #include <user/trace.h>
21 #include <stdbool.h>
22 #include <stdint.h>
23 
24 /**
25  * \brief child IRQ descriptor for cascading IRQ controllers.
26  */
27 struct irq_child {
28 	int enable_count[CONFIG_CORE_COUNT];	/**< IRQ enable counter */
29 	struct list_item list;			/**< head for IRQ descriptors,
30 						  * sharing this interrupt
31 						  */
32 };
33 
34 /**
35  * \brief interrupt client descriptor
36  */
37 struct irq_desc {
38 	int irq;			/**< virtual IRQ number */
39 	void (*handler)(void *arg);	/**< interrupt handler function */
40 	void *handler_arg;		/**< interrupt handler argument */
41 	uint32_t cpu_mask;		/**< a mask of CPUs on which this
42 					  * interrupt is enabled
43 					  */
44 	struct list_item irq_list;	/**< to link to other irq_desc */
45 };
46 
47 /**
48  * \brief cascading IRQ controller operations.
49  */
50 struct irq_cascade_ops {
51 	void (*mask)(struct irq_desc *desc, uint32_t irq,
52 		     unsigned int cpu);				/**< mask */
53 	void (*unmask)(struct irq_desc *desc, uint32_t irq,
54 		       unsigned int cpu);			/**< unmask */
55 };
56 
57 /**
58  * \brief cascading interrupt controller descriptor.
59  */
60 struct irq_cascade_desc {
61 	const char *name;				/**< name of the
62 							  * controller
63 							  */
64 	int irq_base;					/**< first virtual IRQ
65 							  * number, assigned to
66 							  * this controller
67 							  */
68 	const struct irq_cascade_ops *ops;		/**< cascading interrupt
69 							  * controller driver
70 							  * operations
71 							  */
72 	struct irq_desc desc;				/**< the interrupt, that
73 							  * this controller is
74 							  * generating
75 							  */
76 	struct irq_cascade_desc *next;			/**< link to the global
77 							  * list of interrupt
78 							  * controllers
79 							  */
80 	bool global_mask;				/**< the controller
81 							  * cannot mask input
82 							  * interrupts per core
83 							  */
84 	spinlock_t lock;				/**< protect child
85 							  * lists, enable and
86 							  * child counters
87 							  */
88 	int enable_count[CONFIG_CORE_COUNT];		/**< enabled child
89 							  * interrupt counter
90 							  */
91 	unsigned int num_children[CONFIG_CORE_COUNT];	/**< number of children
92 							  */
93 	struct irq_child child[PLATFORM_IRQ_CHILDREN];	/**< array of child
94 							  * lists - one per
95 							  * multiplexed IRQ
96 							  */
97 };
98 
99 /* A descriptor for cascading interrupt controller template */
100 struct irq_cascade_tmpl {
101 	const char *name;
102 	const struct irq_cascade_ops *ops;
103 	int irq;
104 	void (*handler)(void *arg);
105 	bool global_mask;
106 };
107 
108 /**
109  * \brief Cascading interrupt controller root.
110  */
111 struct cascade_root {
112 	spinlock_t lock;		/**< locking mechanism */
113 	struct irq_cascade_desc *list;	/**< list of child cascade irqs */
114 	int last_irq;			/**< last registered cascade irq */
115 };
116 
cascade_root_get(void)117 static inline struct cascade_root *cascade_root_get(void)
118 {
119 	return sof_get()->cascade_root;
120 }
121 
122 /* For i.MX, while building SOF with Zephyr use the interrupt_*
123  * functions from second level interrupt handling and IRQ_STEER.
124  */
125 #if defined(__ZEPHYR__) && defined(CONFIG_IMX)
126 int mux_interrupt_get_irq(unsigned int irq, const char *cascade);
127 int mux_interrupt_register(uint32_t irq, void(*handler)(void *arg), void *arg);
128 void mux_interrupt_unregister(uint32_t irq, const void *arg);
129 uint32_t mux_interrupt_enable(uint32_t irq, void *arg);
130 uint32_t mux_interrupt_disable(uint32_t irq, void *arg);
131 #endif
132 
133 int interrupt_register(uint32_t irq, void(*handler)(void *arg), void *arg);
134 void interrupt_unregister(uint32_t irq, const void *arg);
135 uint32_t interrupt_enable(uint32_t irq, void *arg);
136 uint32_t interrupt_disable(uint32_t irq, void *arg);
137 
138 void platform_interrupt_init(void);
139 
140 void platform_interrupt_set(uint32_t irq);
141 void platform_interrupt_clear(uint32_t irq, uint32_t mask);
142 uint32_t platform_interrupt_get_enabled(void);
143 void interrupt_mask(uint32_t irq, unsigned int cpu);
144 void interrupt_unmask(uint32_t irq, unsigned int cpu);
145 
146 /*
147  * On platforms, supporting cascading interrupts cascaded interrupt numbers
148  * are greater than or equal to PLATFORM_IRQ_HW_NUM
149  */
150 #define interrupt_is_dsp_direct(irq) (!PLATFORM_IRQ_CHILDREN || \
151 					irq < PLATFORM_IRQ_HW_NUM)
152 
153 void interrupt_init(struct sof *sof);
154 int interrupt_cascade_register(const struct irq_cascade_tmpl *tmpl);
155 struct irq_cascade_desc *interrupt_get_parent(uint32_t irq);
156 int interrupt_get_irq(unsigned int irq, const char *cascade);
157 
interrupt_set(int irq)158 static inline void interrupt_set(int irq)
159 {
160 	platform_interrupt_set(irq);
161 }
162 
interrupt_clear_mask(int irq,uint32_t mask)163 static inline void interrupt_clear_mask(int irq, uint32_t mask)
164 {
165 	platform_interrupt_clear(irq, mask);
166 }
167 
interrupt_clear(int irq)168 static inline void interrupt_clear(int irq)
169 {
170 	interrupt_clear_mask(irq, 1);
171 }
172 
interrupt_global_disable(void)173 static inline uint32_t interrupt_global_disable(void)
174 {
175 	return arch_interrupt_global_disable();
176 }
177 
interrupt_global_enable(uint32_t flags)178 static inline void interrupt_global_enable(uint32_t flags)
179 {
180 	arch_interrupt_global_enable(flags);
181 }
182 
183 #if CONFIG_LIBRARY
184 
185 /* temporary fix to remove build warning for testbench that will need shortly
186  * realigned when Zephyr native APIs are used.
187  */
__irq_local_disable(unsigned long flags)188 static inline void __irq_local_disable(unsigned long flags) {}
__irq_local_enable(unsigned long flags)189 static inline void __irq_local_enable(unsigned long flags) {}
190 
191 /* disables all IRQ sources on current core - NO effect on library */
192 #define irq_local_disable(flags)		\
193 	do {					\
194 		flags = 0;			\
195 		__irq_local_disable(flags);	\
196 	} while (0)
197 
198 /* re-enables IRQ sources on current core - NO effect on library*/
199 #define irq_local_enable(flags) \
200 	__irq_local_enable(flags)
201 
202 #else
203 /* disables all IRQ sources on current core */
204 #define irq_local_disable(flags) \
205 	(flags = interrupt_global_disable())
206 
207 /* re-enables IRQ sources on current core */
208 #define irq_local_enable(flags) \
209 	interrupt_global_enable(flags)
210 #endif
211 #endif
212 #endif /* __SOF_DRIVERS_INTERRUPT_H__ */
213