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