| /* |
| * The irq controller for vrc5476. |
| * |
| * Copyright (C) 2001 MontaVista Software Inc. |
| * Author: jsun@mvista.com or jsun@junsun.net |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. |
| * |
| */ |
| #include <linux/init.h> |
| #include <linux/interrupt.h> |
| #include <linux/irq.h> |
| #include <linux/types.h> |
| #include <linux/ptrace.h> |
| |
| #include <asm/system.h> |
| |
| #include <asm/ddb5xxx/ddb5xxx.h> |
| |
| static int irq_base; |
| |
| static void vrc5476_irq_enable(uint irq) |
| { |
| nile4_enable_irq(irq - irq_base); |
| } |
| |
| static void vrc5476_irq_disable(uint irq) |
| { |
| nile4_disable_irq(irq - irq_base); |
| } |
| |
| static unsigned int vrc5476_irq_startup(uint irq) |
| { |
| nile4_enable_irq(irq - irq_base); |
| return 0; |
| } |
| |
| #define vrc5476_irq_shutdown vrc5476_irq_disable |
| |
| static void vrc5476_irq_ack(uint irq) |
| { |
| nile4_clear_irq(irq - irq_base); |
| nile4_disable_irq(irq - irq_base); |
| } |
| |
| static void vrc5476_irq_end(uint irq) |
| { |
| if(!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) |
| vrc5476_irq_enable(irq); |
| } |
| |
| static hw_irq_controller vrc5476_irq_controller = { |
| .typename = "vrc5476", |
| .startup = vrc5476_irq_startup, |
| .shutdown = vrc5476_irq_shutdown, |
| .enable = vrc5476_irq_enable, |
| .disable = vrc5476_irq_disable, |
| .ack = vrc5476_irq_ack, |
| .end = vrc5476_irq_end |
| }; |
| |
| void __init |
| vrc5476_irq_init(u32 base) |
| { |
| u32 i; |
| |
| irq_base = base; |
| for (i= base; i< base + NUM_VRC5476_IRQ; i++) { |
| irq_desc[i].status = IRQ_DISABLED; |
| irq_desc[i].action = NULL; |
| irq_desc[i].depth = 1; |
| irq_desc[i].handler = &vrc5476_irq_controller; |
| } |
| } |
| |
| |
| asmlinkage void |
| vrc5476_irq_dispatch(struct pt_regs *regs) |
| { |
| extern void spurious_interrupt(void); |
| |
| u32 mask; |
| int nile4_irq; |
| |
| mask = nile4_get_irq_stat(0); |
| |
| /* quick check for possible time interrupt */ |
| if (mask & (1 << VRC5476_IRQ_GPT)) { |
| do_IRQ(VRC5476_IRQ_BASE + VRC5476_IRQ_GPT, regs); |
| return; |
| } |
| |
| /* check for i8259 interrupts */ |
| if (mask & (1 << VRC5476_I8259_CASCADE)) { |
| int i8259_irq = nile4_i8259_iack(); |
| do_IRQ(I8259_IRQ_BASE + i8259_irq, regs); |
| return; |
| } |
| |
| /* regular nile4 interrupts (we should not really have any */ |
| for (nile4_irq = 0; mask; nile4_irq++, mask >>= 1) { |
| if (mask & 1) { |
| do_IRQ(VRC5476_IRQ_BASE + nile4_irq, regs); |
| return; |
| } |
| } |
| spurious_interrupt(); |
| } |