xref: /openbmc/linux/arch/mips/sni/irq.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  * This file is subject to the terms and conditions of the GNU General Public
3*1da177e4SLinus Torvalds  * License.  See the file "COPYING" in the main directory of this archive
4*1da177e4SLinus Torvalds  * for more details.
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  * Copyright (C) 1992 Linus Torvalds
7*1da177e4SLinus Torvalds  * Copyright (C) 1994 - 2000 Ralf Baechle
8*1da177e4SLinus Torvalds  */
9*1da177e4SLinus Torvalds #include <linux/delay.h>
10*1da177e4SLinus Torvalds #include <linux/init.h>
11*1da177e4SLinus Torvalds #include <linux/interrupt.h>
12*1da177e4SLinus Torvalds #include <linux/irq.h>
13*1da177e4SLinus Torvalds #include <linux/kernel.h>
14*1da177e4SLinus Torvalds #include <linux/spinlock.h>
15*1da177e4SLinus Torvalds 
16*1da177e4SLinus Torvalds #include <asm/i8259.h>
17*1da177e4SLinus Torvalds #include <asm/io.h>
18*1da177e4SLinus Torvalds #include <asm/sni.h>
19*1da177e4SLinus Torvalds 
20*1da177e4SLinus Torvalds DEFINE_SPINLOCK(pciasic_lock);
21*1da177e4SLinus Torvalds 
22*1da177e4SLinus Torvalds extern asmlinkage void sni_rm200_pci_handle_int(void);
23*1da177e4SLinus Torvalds 
24*1da177e4SLinus Torvalds static void enable_pciasic_irq(unsigned int irq)
25*1da177e4SLinus Torvalds {
26*1da177e4SLinus Torvalds 	unsigned int mask = 1 << (irq - PCIMT_IRQ_INT2);
27*1da177e4SLinus Torvalds 	unsigned long flags;
28*1da177e4SLinus Torvalds 
29*1da177e4SLinus Torvalds 	spin_lock_irqsave(&pciasic_lock, flags);
30*1da177e4SLinus Torvalds 	*(volatile u8 *) PCIMT_IRQSEL |= mask;
31*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&pciasic_lock, flags);
32*1da177e4SLinus Torvalds }
33*1da177e4SLinus Torvalds 
34*1da177e4SLinus Torvalds static unsigned int startup_pciasic_irq(unsigned int irq)
35*1da177e4SLinus Torvalds {
36*1da177e4SLinus Torvalds 	enable_pciasic_irq(irq);
37*1da177e4SLinus Torvalds 	return 0; /* never anything pending */
38*1da177e4SLinus Torvalds }
39*1da177e4SLinus Torvalds 
40*1da177e4SLinus Torvalds #define shutdown_pciasic_irq	disable_pciasic_irq
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds void disable_pciasic_irq(unsigned int irq)
43*1da177e4SLinus Torvalds {
44*1da177e4SLinus Torvalds 	unsigned int mask = ~(1 << (irq - PCIMT_IRQ_INT2));
45*1da177e4SLinus Torvalds 	unsigned long flags;
46*1da177e4SLinus Torvalds 
47*1da177e4SLinus Torvalds 	spin_lock_irqsave(&pciasic_lock, flags);
48*1da177e4SLinus Torvalds 	*(volatile u8 *) PCIMT_IRQSEL &= mask;
49*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&pciasic_lock, flags);
50*1da177e4SLinus Torvalds }
51*1da177e4SLinus Torvalds 
52*1da177e4SLinus Torvalds #define mask_and_ack_pciasic_irq disable_pciasic_irq
53*1da177e4SLinus Torvalds 
54*1da177e4SLinus Torvalds static void end_pciasic_irq(unsigned int irq)
55*1da177e4SLinus Torvalds {
56*1da177e4SLinus Torvalds 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
57*1da177e4SLinus Torvalds 		enable_pciasic_irq(irq);
58*1da177e4SLinus Torvalds }
59*1da177e4SLinus Torvalds 
60*1da177e4SLinus Torvalds static struct hw_interrupt_type pciasic_irq_type = {
61*1da177e4SLinus Torvalds 	"ASIC-PCI",
62*1da177e4SLinus Torvalds 	startup_pciasic_irq,
63*1da177e4SLinus Torvalds 	shutdown_pciasic_irq,
64*1da177e4SLinus Torvalds 	enable_pciasic_irq,
65*1da177e4SLinus Torvalds 	disable_pciasic_irq,
66*1da177e4SLinus Torvalds 	mask_and_ack_pciasic_irq,
67*1da177e4SLinus Torvalds 	end_pciasic_irq,
68*1da177e4SLinus Torvalds 	NULL
69*1da177e4SLinus Torvalds };
70*1da177e4SLinus Torvalds 
71*1da177e4SLinus Torvalds /*
72*1da177e4SLinus Torvalds  * hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
73*1da177e4SLinus Torvalds  * button interrupts.  Later ...
74*1da177e4SLinus Torvalds  */
75*1da177e4SLinus Torvalds void pciasic_hwint0(struct pt_regs *regs)
76*1da177e4SLinus Torvalds {
77*1da177e4SLinus Torvalds 	panic("Received int0 but no handler yet ...");
78*1da177e4SLinus Torvalds }
79*1da177e4SLinus Torvalds 
80*1da177e4SLinus Torvalds /* This interrupt was used for the com1 console on the first prototypes.  */
81*1da177e4SLinus Torvalds void pciasic_hwint2(struct pt_regs *regs)
82*1da177e4SLinus Torvalds {
83*1da177e4SLinus Torvalds 	/* I think this shouldn't happen on production machines.  */
84*1da177e4SLinus Torvalds 	panic("hwint2 and no handler yet");
85*1da177e4SLinus Torvalds }
86*1da177e4SLinus Torvalds 
87*1da177e4SLinus Torvalds /* hwint5 is the r4k count / compare interrupt  */
88*1da177e4SLinus Torvalds void pciasic_hwint5(struct pt_regs *regs)
89*1da177e4SLinus Torvalds {
90*1da177e4SLinus Torvalds 	panic("hwint5 and no handler yet");
91*1da177e4SLinus Torvalds }
92*1da177e4SLinus Torvalds 
93*1da177e4SLinus Torvalds static unsigned int ls1bit8(unsigned int x)
94*1da177e4SLinus Torvalds {
95*1da177e4SLinus Torvalds 	int b = 7, s;
96*1da177e4SLinus Torvalds 
97*1da177e4SLinus Torvalds 	s = 4; if ((x & 0x0f) == 0) s = 0; b -= s; x <<= s;
98*1da177e4SLinus Torvalds 	s = 2; if ((x & 0x30) == 0) s = 0; b -= s; x <<= s;
99*1da177e4SLinus Torvalds 	s = 1; if ((x & 0x40) == 0) s = 0; b -= s;
100*1da177e4SLinus Torvalds 
101*1da177e4SLinus Torvalds 	return b;
102*1da177e4SLinus Torvalds }
103*1da177e4SLinus Torvalds 
104*1da177e4SLinus Torvalds /*
105*1da177e4SLinus Torvalds  * hwint 1 deals with EISA and SCSI interrupts,
106*1da177e4SLinus Torvalds  *
107*1da177e4SLinus Torvalds  * The EISA_INT bit in CSITPEND is high active, all others are low active.
108*1da177e4SLinus Torvalds  */
109*1da177e4SLinus Torvalds void pciasic_hwint1(struct pt_regs *regs)
110*1da177e4SLinus Torvalds {
111*1da177e4SLinus Torvalds 	u8 pend = *(volatile char *)PCIMT_CSITPEND;
112*1da177e4SLinus Torvalds 	unsigned long flags;
113*1da177e4SLinus Torvalds 
114*1da177e4SLinus Torvalds 	if (pend & IT_EISA) {
115*1da177e4SLinus Torvalds 		int irq;
116*1da177e4SLinus Torvalds 		/*
117*1da177e4SLinus Torvalds 		 * Note: ASIC PCI's builtin interrupt achknowledge feature is
118*1da177e4SLinus Torvalds 		 * broken.  Using it may result in loss of some or all i8259
119*1da177e4SLinus Torvalds 		 * interupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
120*1da177e4SLinus Torvalds 		 */
121*1da177e4SLinus Torvalds 		irq = i8259_irq();
122*1da177e4SLinus Torvalds 		if (unlikely(irq < 0))
123*1da177e4SLinus Torvalds 			return;
124*1da177e4SLinus Torvalds 
125*1da177e4SLinus Torvalds 		do_IRQ(irq, regs);
126*1da177e4SLinus Torvalds 	}
127*1da177e4SLinus Torvalds 
128*1da177e4SLinus Torvalds 	if (!(pend & IT_SCSI)) {
129*1da177e4SLinus Torvalds 		flags = read_c0_status();
130*1da177e4SLinus Torvalds 		clear_c0_status(ST0_IM);
131*1da177e4SLinus Torvalds 		do_IRQ(PCIMT_IRQ_SCSI, regs);
132*1da177e4SLinus Torvalds 		write_c0_status(flags);
133*1da177e4SLinus Torvalds 	}
134*1da177e4SLinus Torvalds }
135*1da177e4SLinus Torvalds 
136*1da177e4SLinus Torvalds /*
137*1da177e4SLinus Torvalds  * hwint 3 should deal with the PCI A - D interrupts,
138*1da177e4SLinus Torvalds  */
139*1da177e4SLinus Torvalds void pciasic_hwint3(struct pt_regs *regs)
140*1da177e4SLinus Torvalds {
141*1da177e4SLinus Torvalds 	u8 pend = *(volatile char *)PCIMT_CSITPEND;
142*1da177e4SLinus Torvalds 	int irq;
143*1da177e4SLinus Torvalds 
144*1da177e4SLinus Torvalds 	pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
145*1da177e4SLinus Torvalds 	clear_c0_status(IE_IRQ3);
146*1da177e4SLinus Torvalds 	irq = PCIMT_IRQ_INT2 + ls1bit8(pend);
147*1da177e4SLinus Torvalds 	do_IRQ(irq, regs);
148*1da177e4SLinus Torvalds 	set_c0_status(IE_IRQ3);
149*1da177e4SLinus Torvalds }
150*1da177e4SLinus Torvalds 
151*1da177e4SLinus Torvalds /*
152*1da177e4SLinus Torvalds  * hwint 4 is used for only the onboard PCnet 32.
153*1da177e4SLinus Torvalds  */
154*1da177e4SLinus Torvalds void pciasic_hwint4(struct pt_regs *regs)
155*1da177e4SLinus Torvalds {
156*1da177e4SLinus Torvalds 	clear_c0_status(IE_IRQ4);
157*1da177e4SLinus Torvalds 	do_IRQ(PCIMT_IRQ_ETHERNET, regs);
158*1da177e4SLinus Torvalds 	set_c0_status(IE_IRQ4);
159*1da177e4SLinus Torvalds }
160*1da177e4SLinus Torvalds 
161*1da177e4SLinus Torvalds void __init init_pciasic(void)
162*1da177e4SLinus Torvalds {
163*1da177e4SLinus Torvalds 	unsigned long flags;
164*1da177e4SLinus Torvalds 
165*1da177e4SLinus Torvalds 	spin_lock_irqsave(&pciasic_lock, flags);
166*1da177e4SLinus Torvalds 	* (volatile u8 *) PCIMT_IRQSEL =
167*1da177e4SLinus Torvalds 		IT_EISA | IT_INTA | IT_INTB | IT_INTC | IT_INTD;
168*1da177e4SLinus Torvalds 	spin_unlock_irqrestore(&pciasic_lock, flags);
169*1da177e4SLinus Torvalds }
170*1da177e4SLinus Torvalds 
171*1da177e4SLinus Torvalds /*
172*1da177e4SLinus Torvalds  * On systems with i8259-style interrupt controllers we assume for
173*1da177e4SLinus Torvalds  * driver compatibility reasons interrupts 0 - 15 to be the i8295
174*1da177e4SLinus Torvalds  * interrupts even if the hardware uses a different interrupt numbering.
175*1da177e4SLinus Torvalds  */
176*1da177e4SLinus Torvalds void __init arch_init_irq(void)
177*1da177e4SLinus Torvalds {
178*1da177e4SLinus Torvalds 	int i;
179*1da177e4SLinus Torvalds 
180*1da177e4SLinus Torvalds 	set_except_vector(0, sni_rm200_pci_handle_int);
181*1da177e4SLinus Torvalds 
182*1da177e4SLinus Torvalds 	init_i8259_irqs();			/* Integrated i8259  */
183*1da177e4SLinus Torvalds 	init_pciasic();
184*1da177e4SLinus Torvalds 
185*1da177e4SLinus Torvalds 	/* Actually we've got more interrupts to handle ...  */
186*1da177e4SLinus Torvalds 	for (i = PCIMT_IRQ_INT2; i <= PCIMT_IRQ_ETHERNET; i++) {
187*1da177e4SLinus Torvalds 		irq_desc[i].status     = IRQ_DISABLED;
188*1da177e4SLinus Torvalds 		irq_desc[i].action     = 0;
189*1da177e4SLinus Torvalds 		irq_desc[i].depth      = 1;
190*1da177e4SLinus Torvalds 		irq_desc[i].handler    = &pciasic_irq_type;
191*1da177e4SLinus Torvalds 	}
192*1da177e4SLinus Torvalds 
193*1da177e4SLinus Torvalds 	change_c0_status(ST0_IM, IE_IRQ1|IE_IRQ2|IE_IRQ3|IE_IRQ4);
194*1da177e4SLinus Torvalds }
195