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