Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / arch / v850 / kernel / gbus_int.c
blobb2bcc251f65b8b1ec3c6c9a0d63845c25d99af69
1 /*
2 * arch/v850/kernel/gbus_int.c -- Midas labs GBUS interrupt support
4 * Copyright (C) 2001,02,03 NEC Electronics Corporation
5 * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
7 * This file is subject to the terms and conditions of the GNU General
8 * Public License. See the file COPYING in the main directory of this
9 * archive for more details.
11 * Written by Miles Bader <miles@gnu.org>
14 #include <linux/types.h>
15 #include <linux/init.h>
16 #include <linux/irq.h>
17 #include <linux/interrupt.h>
18 #include <linux/signal.h>
19 #include <linux/kernel.h>
21 #include <asm/machdep.h>
24 /* The number of shared GINT interrupts. */
25 #define NUM_GINTS 4
27 /* For each GINT interrupt, how many GBUS interrupts are using it. */
28 static unsigned gint_num_active_irqs[NUM_GINTS] = { 0 };
30 /* A table of GINTn interrupts we actually use.
31 Note that we don't use GINT0 because all the boards we support treat it
32 specially. */
33 struct used_gint {
34 unsigned gint;
35 unsigned priority;
36 } used_gint[] = {
37 { 1, GBUS_INT_PRIORITY_HIGH },
38 { 3, GBUS_INT_PRIORITY_LOW }
40 #define NUM_USED_GINTS ARRAY_SIZE(used_gint)
42 /* A table of which GINT is used by each GBUS interrupts (they are
43 assigned based on priority). */
44 static unsigned char gbus_int_gint[IRQ_GBUS_INT_NUM];
47 /* Interrupt enabling/disabling. */
49 /* Enable interrupt handling for interrupt IRQ. */
50 void gbus_int_enable_irq (unsigned irq)
52 unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
53 GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
54 |= GBUS_INT_IRQ_MASK (irq);
57 /* Disable interrupt handling for interrupt IRQ. Note that any
58 interrupts received while disabled will be delivered once the
59 interrupt is enabled again, unless they are explicitly cleared using
60 `gbus_int_clear_pending_irq'. */
61 void gbus_int_disable_irq (unsigned irq)
63 unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
64 GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
65 &= ~GBUS_INT_IRQ_MASK (irq);
68 /* Return true if interrupt handling for interrupt IRQ is enabled. */
69 int gbus_int_irq_enabled (unsigned irq)
71 unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
72 return (GBUS_INT_ENABLE (GBUS_INT_IRQ_WORD(irq), gint)
73 & GBUS_INT_IRQ_MASK(irq));
76 /* Disable all GBUS irqs. */
77 void gbus_int_disable_irqs ()
79 unsigned w, n;
80 for (w = 0; w < GBUS_INT_NUM_WORDS; w++)
81 for (n = 0; n < IRQ_GINT_NUM; n++)
82 GBUS_INT_ENABLE (w, n) = 0;
85 /* Clear any pending interrupts for IRQ. */
86 void gbus_int_clear_pending_irq (unsigned irq)
88 GBUS_INT_CLEAR (GBUS_INT_IRQ_WORD(irq)) = GBUS_INT_IRQ_MASK (irq);
91 /* Return true if interrupt IRQ is pending (but disabled). */
92 int gbus_int_irq_pending (unsigned irq)
94 return (GBUS_INT_STATUS (GBUS_INT_IRQ_WORD(irq))
95 & GBUS_INT_IRQ_MASK(irq));
99 /* Delegating interrupts. */
101 /* Handle a shared GINT interrupt by passing to the appropriate GBUS
102 interrupt handler. */
103 static irqreturn_t gbus_int_handle_irq (int irq, void *dev_id,
104 struct pt_regs *regs)
106 unsigned w;
107 irqreturn_t rval = IRQ_NONE;
108 unsigned gint = irq - IRQ_GINT (0);
110 for (w = 0; w < GBUS_INT_NUM_WORDS; w++) {
111 unsigned status = GBUS_INT_STATUS (w);
112 unsigned enable = GBUS_INT_ENABLE (w, gint);
114 /* Only pay attention to enabled interrupts. */
115 status &= enable;
116 if (status) {
117 irq = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD);
118 do {
119 /* There's an active interrupt in word
120 W, find out which one, and call its
121 handler. */
123 while (! (status & 0x1)) {
124 irq++;
125 status >>= 1;
127 status &= ~0x1;
129 /* Recursively call handle_irq to handle it. */
130 handle_irq (irq, regs);
131 rval = IRQ_HANDLED;
132 } while (status);
136 /* Toggle the `all enable' bit back and forth, which should cause
137 another edge transition if there are any other interrupts
138 still pending, and so result in another CPU interrupt. */
139 GBUS_INT_ENABLE (0, gint) &= ~0x1;
140 GBUS_INT_ENABLE (0, gint) |= 0x1;
142 return rval;
146 /* Initialize GBUS interrupt sources. */
148 static void irq_nop (unsigned irq) { }
150 static unsigned gbus_int_startup_irq (unsigned irq)
152 unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
154 if (gint_num_active_irqs[gint] == 0) {
155 /* First enable the CPU interrupt. */
156 int rval =
157 request_irq (IRQ_GINT(gint), gbus_int_handle_irq,
158 IRQF_DISABLED,
159 "gbus_int_handler",
160 &gint_num_active_irqs[gint]);
161 if (rval != 0)
162 return rval;
165 gint_num_active_irqs[gint]++;
167 gbus_int_clear_pending_irq (irq);
168 gbus_int_enable_irq (irq);
170 return 0;
173 static void gbus_int_shutdown_irq (unsigned irq)
175 unsigned gint = gbus_int_gint[irq - GBUS_INT_BASE_IRQ];
177 gbus_int_disable_irq (irq);
179 if (--gint_num_active_irqs[gint] == 0)
180 /* Disable the CPU interrupt. */
181 free_irq (IRQ_GINT(gint), &gint_num_active_irqs[gint]);
184 /* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
185 INITS (which is terminated by an entry with the name field == 0). */
186 void __init gbus_int_init_irq_types (struct gbus_int_irq_init *inits,
187 struct hw_interrupt_type *hw_irq_types)
189 struct gbus_int_irq_init *init;
190 for (init = inits; init->name; init++) {
191 unsigned i;
192 struct hw_interrupt_type *hwit = hw_irq_types++;
194 hwit->typename = init->name;
196 hwit->startup = gbus_int_startup_irq;
197 hwit->shutdown = gbus_int_shutdown_irq;
198 hwit->enable = gbus_int_enable_irq;
199 hwit->disable = gbus_int_disable_irq;
200 hwit->ack = irq_nop;
201 hwit->end = irq_nop;
203 /* Initialize kernel IRQ infrastructure for this interrupt. */
204 init_irq_handlers(init->base, init->num, init->interval, hwit);
206 /* Set the interrupt priorities. */
207 for (i = 0; i < init->num; i++) {
208 unsigned j;
209 for (j = 0; j < NUM_USED_GINTS; j++)
210 if (used_gint[j].priority > init->priority)
211 break;
212 /* Wherever we stopped looking is one past the
213 GINT we want. */
214 gbus_int_gint[init->base + i * init->interval
215 - GBUS_INT_BASE_IRQ]
216 = used_gint[j > 0 ? j - 1 : 0].gint;
222 /* Initialize IRQS. */
224 /* Chip interrupts (GINTn) shared among GBUS interrupts. */
225 static struct hw_interrupt_type gint_hw_itypes[NUM_USED_GINTS];
228 /* GBUS interrupts themselves. */
230 struct gbus_int_irq_init gbus_irq_inits[] __initdata = {
231 /* First set defaults. */
232 { "GBUS_INT", IRQ_GBUS_INT(0), IRQ_GBUS_INT_NUM, 1, 6},
233 { 0 }
235 #define NUM_GBUS_IRQ_INITS (ARRAY_SIZE(gbus_irq_inits) - 1)
237 static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS];
240 /* Initialize GBUS interrupts. */
241 void __init gbus_int_init_irqs (void)
243 unsigned i;
245 /* First initialize the shared gint interrupts. */
246 for (i = 0; i < NUM_USED_GINTS; i++) {
247 unsigned gint = used_gint[i].gint;
248 struct v850e_intc_irq_init gint_irq_init[2];
250 /* We initialize one GINT interrupt at a time. */
251 gint_irq_init[0].name = "GINT";
252 gint_irq_init[0].base = IRQ_GINT (gint);
253 gint_irq_init[0].num = 1;
254 gint_irq_init[0].interval = 1;
255 gint_irq_init[0].priority = used_gint[i].priority;
257 gint_irq_init[1].name = 0; /* Terminate the vector. */
259 v850e_intc_init_irq_types (gint_irq_init, gint_hw_itypes);
262 /* Then the GBUS interrupts. */
263 gbus_int_disable_irqs ();
264 gbus_int_init_irq_types (gbus_irq_inits, gbus_hw_itypes);
265 /* Turn on the `all enable' bits, which are ANDed with
266 individual interrupt enable bits; we only want to bother with
267 the latter. They are the first bit in the first word of each
268 interrupt-enable area. */
269 for (i = 0; i < NUM_USED_GINTS; i++)
270 GBUS_INT_ENABLE (0, used_gint[i].gint) = 0x1;