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