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