xref: /rk3399_rockchip-uboot/drivers/irq/irq-generic.c (revision 331c2375688d79920fb06b8f0c4c52a7df56fb29)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <asm/io.h>
8 #include <asm/u-boot-arm.h>
9 #include <irq-generic.h>
10 #include "irq-gic.h"
11 #include "irq-gpio.h"
12 
13 DECLARE_GLOBAL_DATA_PTR;
14 
15 struct irq_desc {
16 	interrupt_handler_t *handle_irq;
17 	void *data;
18 };
19 
20 static struct irq_desc irqs_desc[PLATFORM_MAX_IRQS_NR];
21 static struct irq_chip *gic_irq_chip, *gpio_irq_chip;
22 static bool initialized;
23 
24 static int bad_irq(int irq)
25 {
26 	if (irq >= PLATFORM_MAX_IRQS_NR) {
27 		IRQ_W("IRQ %d is out of max supported IRQ(%d)\n",
28 		      irq, PLATFORM_MAX_IRQS_NR);
29 		return -EINVAL;
30 	}
31 
32 	if (!irqs_desc[irq].handle_irq)
33 		return -EINVAL;
34 
35 	if (!initialized) {
36 		IRQ_W("Interrupt framework is not initialized\n");
37 		return -EINVAL;
38 	}
39 
40 	return 0;
41 }
42 
43 /* general interrupt handler for gpio chip */
44 void __generic_gpio_handle_irq(int irq)
45 {
46 	if (bad_irq(irq))
47 		return;
48 
49 	if (irq < PLATFORM_GIC_IRQS_NR) {
50 		IRQ_W("IRQ %d is not a GPIO irq\n", irq);
51 		return;
52 	}
53 
54 	if (irqs_desc[irq].handle_irq)
55 		irqs_desc[irq].handle_irq(irq, irqs_desc[irq].data);
56 }
57 
58 void __do_generic_irq_handler(void)
59 {
60 	u32 irq = gic_irq_chip->irq_get();
61 
62 	if (irq < PLATFORM_GIC_IRQS_NR) {
63 		if (irqs_desc[irq].handle_irq)
64 			irqs_desc[irq].handle_irq(irq, irqs_desc[irq].data);
65 	}
66 
67 	gic_irq_chip->irq_eoi(irq);
68 }
69 
70 int irq_is_busy(int irq)
71 {
72 	return (irq >= 0 && irqs_desc[irq].handle_irq) ? -EBUSY : 0;
73 }
74 
75 static int bad_irq_chip(struct irq_chip *chip)
76 {
77 	if (!chip->name ||
78 	    !chip->irq_init ||
79 	    !chip->irq_enable ||
80 	    !chip->irq_disable ||
81 	    !chip->irq_set_type)
82 		return -EINVAL;
83 
84 	return 0;
85 }
86 
87 static int __do_arch_irq_init(void)
88 {
89 	int irq, err = -EINVAL;
90 
91 	/* After relocation done, bss data initialized */
92 	if (!(gd->flags & GD_FLG_RELOC)) {
93 		IRQ_W("Interrupt framework should initialize after reloc\n");
94 		return -EINVAL;
95 	}
96 
97 	/*
98 	 * We set true before arch_gpio_irq_init() to avoid fail when
99 	 * request irq for gpio banks.
100 	 */
101 	initialized = true;
102 
103 	for (irq = 0; irq < PLATFORM_MAX_IRQS_NR; irq++) {
104 		irqs_desc[irq].handle_irq = NULL;
105 		irqs_desc[irq].data = NULL;
106 	}
107 
108 	gic_irq_chip = arch_gic_irq_init();
109 	if (bad_irq_chip(gic_irq_chip)) {
110 		IRQ_E("Bad gic irq chip\n");
111 		goto out;
112 	}
113 
114 	gpio_irq_chip = arch_gpio_irq_init();
115 	if (bad_irq_chip(gpio_irq_chip)) {
116 		IRQ_E("Bad gpio irq chip\n");
117 		goto out;
118 	}
119 
120 	err = gic_irq_chip->irq_init();
121 	if (err) {
122 		IRQ_E("GIC interrupt initial failed, ret=%d\n", err);
123 		goto out;
124 	}
125 
126 	err = gpio_irq_chip->irq_init();
127 	if (err) {
128 		IRQ_E("GPIO interrupt initial failed, ret=%d\n", err);
129 		goto out;
130 	}
131 
132 	return 0;
133 
134 out:
135 	initialized = false;
136 
137 	return err;
138 }
139 
140 int irq_handler_enable(int irq)
141 {
142 	if (bad_irq(irq))
143 		return -EINVAL;
144 
145 	if (irq < PLATFORM_GIC_IRQS_NR)
146 		return gic_irq_chip->irq_enable(irq);
147 	else
148 		return gpio_irq_chip->irq_enable(irq);
149 }
150 
151 int irq_handler_disable(int irq)
152 {
153 	if (bad_irq(irq))
154 		return -EINVAL;
155 
156 	if (irq < PLATFORM_GIC_IRQS_NR)
157 		return gic_irq_chip->irq_disable(irq);
158 	else
159 		return gpio_irq_chip->irq_disable(irq);
160 }
161 
162 int irq_set_irq_type(int irq, unsigned int type)
163 {
164 	if (bad_irq(irq))
165 		return -EINVAL;
166 
167 	if (irq < PLATFORM_GIC_IRQS_NR)
168 		return gic_irq_chip->irq_set_type(irq, type);
169 	else
170 		return gpio_irq_chip->irq_set_type(irq, type);
171 }
172 
173 int irq_revert_irq_type(int irq)
174 {
175 	if (bad_irq(irq))
176 		return -EINVAL;
177 
178 	if (irq < PLATFORM_GIC_IRQS_NR)
179 		return 0;
180 	else
181 		return gpio_irq_chip->irq_revert_type(irq);
182 }
183 
184 int irq_get_gpio_level(int irq)
185 {
186 	if (bad_irq(irq))
187 		return -EINVAL;
188 
189 	if (irq < PLATFORM_GIC_IRQS_NR)
190 		return 0;
191 	else
192 		return gpio_irq_chip->irq_get_gpio_level(irq);
193 }
194 
195 void irq_install_handler(int irq, interrupt_handler_t *handler, void *data)
196 {
197 	if (irq >= PLATFORM_MAX_IRQS_NR) {
198 		IRQ_W("IRQ %d is out of max supported IRQ(%d)\n",
199 		      irq, PLATFORM_MAX_IRQS_NR);
200 		return;
201 	}
202 
203 	if (!handler || irqs_desc[irq].handle_irq)
204 		return;
205 
206 	if (!initialized) {
207 		IRQ_W("Interrupt framework is not initialized\n");
208 		return;
209 	}
210 
211 	irqs_desc[irq].handle_irq = handler;
212 	irqs_desc[irq].data = data;
213 }
214 
215 void irq_free_handler(int irq)
216 {
217 	if (irq_handler_disable(irq))
218 		return;
219 
220 	irqs_desc[irq].handle_irq = NULL;
221 	irqs_desc[irq].data = NULL;
222 }
223 
224 int irqs_suspend(void)
225 {
226 	int err;
227 
228 	err = gic_irq_chip->irq_suspend();
229 	if (err) {
230 		IRQ_E("IRQs suspend failed, ret=%d\n", err);
231 		return err;
232 	}
233 
234 	return 0;
235 }
236 
237 int irqs_resume(void)
238 {
239 	int err;
240 
241 	err = gic_irq_chip->irq_resume();
242 	if (err) {
243 		IRQ_E("IRQs resume failed, ret=%d\n", err);
244 		return err;
245 	}
246 
247 	return 0;
248 }
249 
250 #ifdef CONFIG_ARM64
251 static void cpu_local_irq_enable(void)
252 {
253 	asm volatile("msr daifclr, #0x02");
254 }
255 
256 static int cpu_local_irq_disable(void)
257 {
258 	asm volatile("msr daifset, #0x02");
259 	return 0;
260 }
261 
262 void do_irq(struct pt_regs *pt_regs, unsigned int esr)
263 {
264 #ifdef CONFIG_ROCKCHIP_DEBUGGER
265 	printf("\n>>> Rockchip Debugger:\n");
266 	show_regs(pt_regs);
267 #endif
268 
269 	__do_generic_irq_handler();
270 }
271 #else
272 static void cpu_local_irq_enable(void)
273 {
274 	unsigned long cpsr;
275 
276 	__asm__ __volatile__("mrs %0, cpsr\n"
277 			     "bic %0, %0, #0x80\n"
278 			     "msr cpsr_c, %0"
279 			     : "=r" (cpsr) : : "memory");
280 }
281 
282 static int cpu_local_irq_disable(void)
283 {
284 	unsigned long old_cpsr, new_cpsr;
285 
286 	__asm__ __volatile__("mrs %0, cpsr\n"
287 			     "orr %1, %0, #0xc0\n"
288 			     "msr cpsr_c, %1"
289 			     : "=r" (old_cpsr), "=r" (new_cpsr)
290 			     :
291 			     : "memory");
292 
293 	return (old_cpsr & 0x80) == 0;
294 }
295 
296 void do_irq(struct pt_regs *pt_regs)
297 {
298 #ifdef CONFIG_ROCKCHIP_DEBUGGER
299 	printf("\n>>> Rockchp Debugger:\n");
300 	show_regs(pt_regs);
301 #endif
302 
303 	__do_generic_irq_handler();
304 }
305 #endif
306 
307 int arch_interrupt_init(void)
308 {
309 #ifndef CONFIG_ARM64
310 	unsigned long cpsr __maybe_unused;
311 
312 	/* stack has been reserved in: arch_reserve_stacks() */
313 	IRQ_STACK_START = gd->irq_sp;
314 	IRQ_STACK_START_IN = gd->irq_sp;
315 
316 	__asm__ __volatile__("mrs %0, cpsr\n"
317 			     : "=r" (cpsr)
318 			     :
319 			     : "memory");
320 
321 	__asm__ __volatile__("msr cpsr_c, %0\n"
322 			     "mov sp, %1\n"
323 			     :
324 			     : "r" (IRQ_MODE | I_BIT |
325 				    F_BIT | (cpsr & ~FIQ_MODE)),
326 			       "r" (IRQ_STACK_START)
327 			     : "memory");
328 
329 	__asm__ __volatile__("msr cpsr_c, %0"
330 			     :
331 			     : "r" (cpsr)
332 			     : "memory");
333 #endif
334 	return __do_arch_irq_init();
335 }
336 
337 int interrupt_init(void)
338 {
339 	return arch_interrupt_init();
340 }
341 
342 void enable_interrupts(void)
343 {
344 	cpu_local_irq_enable();
345 }
346 
347 int disable_interrupts(void)
348 {
349 	return cpu_local_irq_disable();
350 }
351