Commit | Line | Data |
---|---|---|
9918cda5 UKK |
1 | /* |
2 | * arch/arm/mach-ns9xxx/irq.c | |
3 | * | |
4 | * Copyright (C) 2006,2007 by Digi International Inc. | |
5 | * All rights reserved. | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License version 2 as published by | |
9 | * the Free Software Foundation. | |
10 | */ | |
11 | #include <linux/interrupt.h> | |
5e69b945 | 12 | #include <linux/kernel_stat.h> |
fced80c7 | 13 | #include <linux/io.h> |
9918cda5 | 14 | #include <asm/mach/irq.h> |
a09e64fb RK |
15 | #include <mach/regs-sys-common.h> |
16 | #include <mach/irqs.h> | |
17 | #include <mach/board.h> | |
9918cda5 UKK |
18 | |
19 | #include "generic.h" | |
20 | ||
ed6f5987 UKK |
21 | /* simple interrupt prio table: prio(x) < prio(y) <=> x < y */ |
22 | #define irq2prio(i) (i) | |
23 | #define prio2irq(p) (p) | |
24 | ||
9918cda5 UKK |
25 | static void ns9xxx_mask_irq(unsigned int irq) |
26 | { | |
27 | /* XXX: better use cpp symbols */ | |
ed6f5987 UKK |
28 | int prio = irq2prio(irq); |
29 | u32 ic = __raw_readl(SYS_IC(prio / 4)); | |
30 | ic &= ~(1 << (7 + 8 * (3 - (prio & 3)))); | |
31 | __raw_writel(ic, SYS_IC(prio / 4)); | |
9918cda5 UKK |
32 | } |
33 | ||
34 | static void ns9xxx_ack_irq(unsigned int irq) | |
35 | { | |
361c7ad6 | 36 | __raw_writel(0, SYS_ISRADDR); |
9918cda5 UKK |
37 | } |
38 | ||
39 | static void ns9xxx_maskack_irq(unsigned int irq) | |
40 | { | |
41 | ns9xxx_mask_irq(irq); | |
42 | ns9xxx_ack_irq(irq); | |
43 | } | |
44 | ||
45 | static void ns9xxx_unmask_irq(unsigned int irq) | |
46 | { | |
47 | /* XXX: better use cpp symbols */ | |
ed6f5987 UKK |
48 | int prio = irq2prio(irq); |
49 | u32 ic = __raw_readl(SYS_IC(prio / 4)); | |
50 | ic |= 1 << (7 + 8 * (3 - (prio & 3))); | |
51 | __raw_writel(ic, SYS_IC(prio / 4)); | |
9918cda5 UKK |
52 | } |
53 | ||
54 | static struct irq_chip ns9xxx_chip = { | |
55 | .ack = ns9xxx_ack_irq, | |
56 | .mask = ns9xxx_mask_irq, | |
57 | .mask_ack = ns9xxx_maskack_irq, | |
58 | .unmask = ns9xxx_unmask_irq, | |
59 | }; | |
60 | ||
5e69b945 UKK |
61 | #if 0 |
62 | #define handle_irq handle_level_irq | |
63 | #else | |
21f20b69 | 64 | static void handle_prio_irq(unsigned int irq, struct irq_desc *desc) |
5e69b945 UKK |
65 | { |
66 | unsigned int cpu = smp_processor_id(); | |
67 | struct irqaction *action; | |
68 | irqreturn_t action_ret; | |
69 | ||
70 | spin_lock(&desc->lock); | |
71 | ||
a13c8195 | 72 | BUG_ON(desc->status & IRQ_INPROGRESS); |
5e69b945 UKK |
73 | |
74 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | |
75 | kstat_cpu(cpu).irqs[irq]++; | |
76 | ||
77 | action = desc->action; | |
78 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) | |
a13c8195 | 79 | goto out_mask; |
5e69b945 UKK |
80 | |
81 | desc->status |= IRQ_INPROGRESS; | |
82 | spin_unlock(&desc->lock); | |
83 | ||
84 | action_ret = handle_IRQ_event(irq, action); | |
85 | ||
a57a0b1d UKK |
86 | /* XXX: There is no direct way to access noirqdebug, so check |
87 | * unconditionally for spurious irqs... | |
88 | * Maybe this function should go to kernel/irq/chip.c? */ | |
89 | note_interrupt(irq, desc, action_ret); | |
90 | ||
5e69b945 UKK |
91 | spin_lock(&desc->lock); |
92 | desc->status &= ~IRQ_INPROGRESS; | |
5e69b945 | 93 | |
a13c8195 UKK |
94 | if (desc->status & IRQ_DISABLED) |
95 | out_mask: | |
96 | desc->chip->mask(irq); | |
97 | ||
98 | /* ack unconditionally to unmask lower prio irqs */ | |
99 | desc->chip->ack(irq); | |
100 | ||
5e69b945 UKK |
101 | spin_unlock(&desc->lock); |
102 | } | |
103 | #define handle_irq handle_prio_irq | |
104 | #endif | |
105 | ||
9918cda5 UKK |
106 | void __init ns9xxx_init_irq(void) |
107 | { | |
108 | int i; | |
109 | ||
110 | /* disable all IRQs */ | |
111 | for (i = 0; i < 8; ++i) | |
ed6f5987 UKK |
112 | __raw_writel(prio2irq(4 * i) << 24 | |
113 | prio2irq(4 * i + 1) << 16 | | |
114 | prio2irq(4 * i + 2) << 8 | | |
115 | prio2irq(4 * i + 3), | |
116 | SYS_IC(i)); | |
9918cda5 | 117 | |
9918cda5 | 118 | for (i = 0; i < 32; ++i) |
ed6f5987 | 119 | __raw_writel(prio2irq(i), SYS_IVA(i)); |
9918cda5 | 120 | |
724ce5ee | 121 | for (i = 0; i <= 31; ++i) { |
9918cda5 | 122 | set_irq_chip(i, &ns9xxx_chip); |
5e69b945 | 123 | set_irq_handler(i, handle_irq); |
9918cda5 UKK |
124 | set_irq_flags(i, IRQF_VALID); |
125 | } | |
126 | } |