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