1 /*
2 * IRQ vector handles
3 *
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file "COPYING" in the main directory of this archive
6 * for more details.
7 *
8 * Copyright (C) 1995, 1996, 1997 by Ralf Baechle
9 * Copyright (C) 2001 by Liam Davies (ldavies@agile.tv)
10 *
11 */
12
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/spinlock.h>
16 #include <linux/interrupt.h>
17 #include <linux/ioport.h>
18
19 #include <asm/bootinfo.h>
20 #include <asm/i8259.h>
21 #include <asm/io.h>
22 #include <asm/irq.h>
23 #include <asm/mipsregs.h>
24 #include <asm/system.h>
25
26 #include <asm/cobalt/cobalt.h>
27
28 /* Cobalt Exception handler */
29 extern void cobalt_handle_int(void);
30
31 /* Via masking routines */
32 extern void unmask_irq(unsigned int irqr);
33 extern void mask_irq(unsigned int irq);
34
35
36 /*
37 * We have two types of interrupts that we handle, ones that come
38 * in through the CPU interrupt lines, and ones that come in on
39 * the via chip. The CPU mappings are:
40 * 0,1 - S/W (ignored)
41 * 2 - Galileo chip (timer)
42 * 3 - Tulip 0 + NCR SCSI
43 * 4 - Tulip 1
44 * 5 - 16550 UART
45 * 6 - VIA southbridge PIC
46 * 7 - unused
47 *
48 * The VIA chip is a master/slave 8259 setup and has the
49 * following interrupts
50 * 8 - RTC
51 * 9 - PCI
52 * 14 - IDE0
53 * 15 - IDE1
54 *
55 * In the table we use a 1 to indicate that we use a VIA interrupt
56 * line, and IE_IRQx to indicate that we use a CPU interrupt line
57 *
58 * We map all of these onto linux IRQ #s 0-15 and forget the rest
59 */
60 #define NOINT_LINE 0
61 #define CPUINT_LINE(x) IE_IRQ##x
62 #define VIAINT_LINE 1
63
64 #define COBALT_IRQS 16
65
66 static unsigned short irqnr_to_type[COBALT_IRQS] =
67 { CPUINT_LINE(0), NOINT_LINE, VIAINT_LINE, NOINT_LINE,
68 CPUINT_LINE(1), NOINT_LINE, NOINT_LINE, CPUINT_LINE(3),
69 VIAINT_LINE, VIAINT_LINE, NOINT_LINE, NOINT_LINE,
70 NOINT_LINE, CPUINT_LINE(2), VIAINT_LINE, VIAINT_LINE };
71
72 /*
73 * Cobalt CPU irq
74 */
75
enable_cpu_irq(unsigned int irq)76 static void enable_cpu_irq(unsigned int irq)
77 {
78 unsigned long flags;
79
80 save_and_cli(flags);
81 change_c0_status(irqnr_to_type[irq], irqnr_to_type[irq]);
82 restore_flags(flags);
83 }
84
startup_cpu_irq(unsigned int irq)85 static unsigned startup_cpu_irq(unsigned int irq)
86 {
87 enable_cpu_irq(irq);
88
89 return 0;
90 }
91
disable_cpu_irq(unsigned int irq)92 static void disable_cpu_irq(unsigned int irq)
93 {
94 unsigned long flags;
95
96 save_and_cli(flags);
97 change_c0_status(irqnr_to_type[irq], ~(irqnr_to_type[irq]));
98 restore_flags(flags);
99 }
100
101 #define shutdown_cpu_irq disable_cpu_irq
102 #define mask_and_ack_cpu_irq disable_cpu_irq
103
end_cpu_irq(unsigned int irq)104 static void end_cpu_irq(unsigned int irq)
105 {
106 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
107 enable_cpu_irq(irq);
108 }
109
110 static struct hw_interrupt_type cobalt_cpu_irq_type = {
111 "Cobalt CPU",
112 startup_cpu_irq,
113 shutdown_cpu_irq,
114 enable_cpu_irq,
115 disable_cpu_irq,
116 mask_and_ack_cpu_irq,
117 end_cpu_irq,
118 NULL
119 };
120
init_IRQ(void)121 void __init init_IRQ(void)
122 {
123 int i;
124
125 /* Initialise all of the IRQ descriptors */
126 init_i8259_irqs();
127
128 /* Map the irqnr to the type int we have */
129 for (i=0; i < COBALT_IRQS; i++) {
130 if (irqnr_to_type[i] >= CPUINT_LINE(0))
131 /* cobalt_cpu_irq_type */
132 irq_desc[i].handler = &cobalt_cpu_irq_type;
133 }
134
135 /* Mask all cpu interrupts
136 (except IE4, we already masked those at VIA level) */
137 clear_c0_status(ST0_IM);
138 set_c0_status(IE_IRQ4);
139
140 cli();
141
142 set_except_vector(0, cobalt_handle_int);
143 }
144