aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2011-05-16 08:27:09 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2011-05-16 08:27:09 -0400
commitf29251ff532ca1124d14a03b040ba097edc6e9c0 (patch)
treec910741c4116811b4d4cec8f621c9168fe67a94a
parent1cf02bbd51a1ff74a31f88b1f654243a4affef8d (diff)
parent667a11facee70c0bd15cf07946fba71236490e07 (diff)
Merge branch 'devel-genirq' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6 into devel-stable
-rw-r--r--arch/arm/mach-omap2/irq.c97
1 files changed, 25 insertions, 72 deletions
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 237e4530abf2..3af2b7a1045e 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -73,83 +73,18 @@ static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg)
73 return __raw_readl(bank->base_reg + reg); 73 return __raw_readl(bank->base_reg + reg);
74} 74}
75 75
76static int previous_irq;
77
78/*
79 * On 34xx we can get occasional spurious interrupts if the ack from
80 * an interrupt handler does not get posted before we unmask. Warn about
81 * the interrupt handlers that need to flush posted writes.
82 */
83static int omap_check_spurious(unsigned int irq)
84{
85 u32 sir, spurious;
86
87 sir = intc_bank_read_reg(&irq_banks[0], INTC_SIR);
88 spurious = sir >> 7;
89
90 if (spurious) {
91 printk(KERN_WARNING "Spurious irq %i: 0x%08x, please flush "
92 "posted write for irq %i\n",
93 irq, sir, previous_irq);
94 return spurious;
95 }
96
97 return 0;
98}
99
100/* XXX: FIQ and additional INTC support (only MPU at the moment) */ 76/* XXX: FIQ and additional INTC support (only MPU at the moment) */
101static void omap_ack_irq(struct irq_data *d) 77static void omap_ack_irq(struct irq_data *d)
102{ 78{
103 intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL); 79 intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL);
104} 80}
105 81
106static void omap_mask_irq(struct irq_data *d)
107{
108 unsigned int irq = d->irq;
109 int offset = irq & (~(IRQ_BITS_PER_REG - 1));
110
111 if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
112 int spurious = 0;
113
114 /*
115 * INT_34XX_GPT12_IRQ is also the spurious irq. Maybe because
116 * it is the highest irq number?
117 */
118 if (irq == INT_34XX_GPT12_IRQ)
119 spurious = omap_check_spurious(irq);
120
121 if (!spurious)
122 previous_irq = irq;
123 }
124
125 irq &= (IRQ_BITS_PER_REG - 1);
126
127 intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset);
128}
129
130static void omap_unmask_irq(struct irq_data *d)
131{
132 unsigned int irq = d->irq;
133 int offset = irq & (~(IRQ_BITS_PER_REG - 1));
134
135 irq &= (IRQ_BITS_PER_REG - 1);
136
137 intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_CLEAR0 + offset);
138}
139
140static void omap_mask_ack_irq(struct irq_data *d) 82static void omap_mask_ack_irq(struct irq_data *d)
141{ 83{
142 omap_mask_irq(d); 84 irq_gc_mask_disable_reg(d);
143 omap_ack_irq(d); 85 omap_ack_irq(d);
144} 86}
145 87
146static struct irq_chip omap_irq_chip = {
147 .name = "INTC",
148 .irq_ack = omap_mask_ack_irq,
149 .irq_mask = omap_mask_irq,
150 .irq_unmask = omap_unmask_irq,
151};
152
153static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank) 88static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
154{ 89{
155 unsigned long tmp; 90 unsigned long tmp;
@@ -186,11 +121,31 @@ int omap_irq_pending(void)
186 return 0; 121 return 0;
187} 122}
188 123
124static __init void
125omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
126{
127 struct irq_chip_generic *gc;
128 struct irq_chip_type *ct;
129
130 gc = irq_alloc_generic_chip("INTC", 1, irq_start, base,
131 handle_level_irq);
132 ct = gc->chip_types;
133 ct->chip.irq_ack = omap_mask_ack_irq;
134 ct->chip.irq_mask = irq_gc_mask_disable_reg;
135 ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
136
137 ct->regs.ack = INTC_CONTROL;
138 ct->regs.enable = INTC_MIR_CLEAR0;
139 ct->regs.disable = INTC_MIR_SET0;
140 irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
141 IRQ_NOREQUEST | IRQ_NOPROBE, 0);
142}
143
189void __init omap_init_irq(void) 144void __init omap_init_irq(void)
190{ 145{
191 unsigned long nr_of_irqs = 0; 146 unsigned long nr_of_irqs = 0;
192 unsigned int nr_banks = 0; 147 unsigned int nr_banks = 0;
193 int i; 148 int i, j;
194 149
195 for (i = 0; i < ARRAY_SIZE(irq_banks); i++) { 150 for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
196 unsigned long base = 0; 151 unsigned long base = 0;
@@ -215,17 +170,15 @@ void __init omap_init_irq(void)
215 170
216 omap_irq_bank_init_one(bank); 171 omap_irq_bank_init_one(bank);
217 172
173 for (i = 0, j = 0; i < bank->nr_irqs; i += 32, j += 0x20)
174 omap_alloc_gc(bank->base_reg + j, i, 32);
175
218 nr_of_irqs += bank->nr_irqs; 176 nr_of_irqs += bank->nr_irqs;
219 nr_banks++; 177 nr_banks++;
220 } 178 }
221 179
222 printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n", 180 printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n",
223 nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : ""); 181 nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
224
225 for (i = 0; i < nr_of_irqs; i++) {
226 irq_set_chip_and_handler(i, &omap_irq_chip, handle_level_irq);
227 set_irq_flags(i, IRQF_VALID);
228 }
229} 182}
230 183
231#ifdef CONFIG_ARCH_OMAP3 184#ifdef CONFIG_ARCH_OMAP3