xref: /openbmc/linux/arch/alpha/kernel/irq_pyxis.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *	linux/arch/alpha/kernel/irq_pyxis.c
3*1da177e4SLinus Torvalds  *
4*1da177e4SLinus Torvalds  * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
5*1da177e4SLinus Torvalds  *
6*1da177e4SLinus Torvalds  * IRQ Code common to all PYXIS core logic chips.
7*1da177e4SLinus Torvalds  */
8*1da177e4SLinus Torvalds 
9*1da177e4SLinus Torvalds #include <linux/init.h>
10*1da177e4SLinus Torvalds #include <linux/sched.h>
11*1da177e4SLinus Torvalds #include <linux/irq.h>
12*1da177e4SLinus Torvalds 
13*1da177e4SLinus Torvalds #include <asm/io.h>
14*1da177e4SLinus Torvalds #include <asm/core_cia.h>
15*1da177e4SLinus Torvalds 
16*1da177e4SLinus Torvalds #include "proto.h"
17*1da177e4SLinus Torvalds #include "irq_impl.h"
18*1da177e4SLinus Torvalds 
19*1da177e4SLinus Torvalds 
20*1da177e4SLinus Torvalds /* Note mask bit is true for ENABLED irqs.  */
21*1da177e4SLinus Torvalds static unsigned long cached_irq_mask;
22*1da177e4SLinus Torvalds 
23*1da177e4SLinus Torvalds static inline void
24*1da177e4SLinus Torvalds pyxis_update_irq_hw(unsigned long mask)
25*1da177e4SLinus Torvalds {
26*1da177e4SLinus Torvalds 	*(vulp)PYXIS_INT_MASK = mask;
27*1da177e4SLinus Torvalds 	mb();
28*1da177e4SLinus Torvalds 	*(vulp)PYXIS_INT_MASK;
29*1da177e4SLinus Torvalds }
30*1da177e4SLinus Torvalds 
31*1da177e4SLinus Torvalds static inline void
32*1da177e4SLinus Torvalds pyxis_enable_irq(unsigned int irq)
33*1da177e4SLinus Torvalds {
34*1da177e4SLinus Torvalds 	pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
35*1da177e4SLinus Torvalds }
36*1da177e4SLinus Torvalds 
37*1da177e4SLinus Torvalds static void
38*1da177e4SLinus Torvalds pyxis_disable_irq(unsigned int irq)
39*1da177e4SLinus Torvalds {
40*1da177e4SLinus Torvalds 	pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
41*1da177e4SLinus Torvalds }
42*1da177e4SLinus Torvalds 
43*1da177e4SLinus Torvalds static unsigned int
44*1da177e4SLinus Torvalds pyxis_startup_irq(unsigned int irq)
45*1da177e4SLinus Torvalds {
46*1da177e4SLinus Torvalds 	pyxis_enable_irq(irq);
47*1da177e4SLinus Torvalds 	return 0;
48*1da177e4SLinus Torvalds }
49*1da177e4SLinus Torvalds 
50*1da177e4SLinus Torvalds static void
51*1da177e4SLinus Torvalds pyxis_end_irq(unsigned int irq)
52*1da177e4SLinus Torvalds {
53*1da177e4SLinus Torvalds 	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
54*1da177e4SLinus Torvalds 		pyxis_enable_irq(irq);
55*1da177e4SLinus Torvalds }
56*1da177e4SLinus Torvalds 
57*1da177e4SLinus Torvalds static void
58*1da177e4SLinus Torvalds pyxis_mask_and_ack_irq(unsigned int irq)
59*1da177e4SLinus Torvalds {
60*1da177e4SLinus Torvalds 	unsigned long bit = 1UL << (irq - 16);
61*1da177e4SLinus Torvalds 	unsigned long mask = cached_irq_mask &= ~bit;
62*1da177e4SLinus Torvalds 
63*1da177e4SLinus Torvalds 	/* Disable the interrupt.  */
64*1da177e4SLinus Torvalds 	*(vulp)PYXIS_INT_MASK = mask;
65*1da177e4SLinus Torvalds 	wmb();
66*1da177e4SLinus Torvalds 	/* Ack PYXIS PCI interrupt.  */
67*1da177e4SLinus Torvalds 	*(vulp)PYXIS_INT_REQ = bit;
68*1da177e4SLinus Torvalds 	mb();
69*1da177e4SLinus Torvalds 	/* Re-read to force both writes.  */
70*1da177e4SLinus Torvalds 	*(vulp)PYXIS_INT_MASK;
71*1da177e4SLinus Torvalds }
72*1da177e4SLinus Torvalds 
73*1da177e4SLinus Torvalds static struct hw_interrupt_type pyxis_irq_type = {
74*1da177e4SLinus Torvalds 	.typename	= "PYXIS",
75*1da177e4SLinus Torvalds 	.startup	= pyxis_startup_irq,
76*1da177e4SLinus Torvalds 	.shutdown	= pyxis_disable_irq,
77*1da177e4SLinus Torvalds 	.enable		= pyxis_enable_irq,
78*1da177e4SLinus Torvalds 	.disable	= pyxis_disable_irq,
79*1da177e4SLinus Torvalds 	.ack		= pyxis_mask_and_ack_irq,
80*1da177e4SLinus Torvalds 	.end		= pyxis_end_irq,
81*1da177e4SLinus Torvalds };
82*1da177e4SLinus Torvalds 
83*1da177e4SLinus Torvalds void
84*1da177e4SLinus Torvalds pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
85*1da177e4SLinus Torvalds {
86*1da177e4SLinus Torvalds 	unsigned long pld;
87*1da177e4SLinus Torvalds 	unsigned int i;
88*1da177e4SLinus Torvalds 
89*1da177e4SLinus Torvalds 	/* Read the interrupt summary register of PYXIS */
90*1da177e4SLinus Torvalds 	pld = *(vulp)PYXIS_INT_REQ;
91*1da177e4SLinus Torvalds 	pld &= cached_irq_mask;
92*1da177e4SLinus Torvalds 
93*1da177e4SLinus Torvalds 	/*
94*1da177e4SLinus Torvalds 	 * Now for every possible bit set, work through them and call
95*1da177e4SLinus Torvalds 	 * the appropriate interrupt handler.
96*1da177e4SLinus Torvalds 	 */
97*1da177e4SLinus Torvalds 	while (pld) {
98*1da177e4SLinus Torvalds 		i = ffz(~pld);
99*1da177e4SLinus Torvalds 		pld &= pld - 1; /* clear least bit set */
100*1da177e4SLinus Torvalds 		if (i == 7)
101*1da177e4SLinus Torvalds 			isa_device_interrupt(vector, regs);
102*1da177e4SLinus Torvalds 		else
103*1da177e4SLinus Torvalds 			handle_irq(16+i, regs);
104*1da177e4SLinus Torvalds 	}
105*1da177e4SLinus Torvalds }
106*1da177e4SLinus Torvalds 
107*1da177e4SLinus Torvalds void __init
108*1da177e4SLinus Torvalds init_pyxis_irqs(unsigned long ignore_mask)
109*1da177e4SLinus Torvalds {
110*1da177e4SLinus Torvalds 	long i;
111*1da177e4SLinus Torvalds 
112*1da177e4SLinus Torvalds 	*(vulp)PYXIS_INT_MASK = 0;		/* disable all */
113*1da177e4SLinus Torvalds 	*(vulp)PYXIS_INT_REQ  = -1;		/* flush all */
114*1da177e4SLinus Torvalds 	mb();
115*1da177e4SLinus Torvalds 
116*1da177e4SLinus Torvalds 	/* Send -INTA pulses to clear any pending interrupts ...*/
117*1da177e4SLinus Torvalds 	*(vuip) CIA_IACK_SC;
118*1da177e4SLinus Torvalds 
119*1da177e4SLinus Torvalds 	for (i = 16; i < 48; ++i) {
120*1da177e4SLinus Torvalds 		if ((ignore_mask >> i) & 1)
121*1da177e4SLinus Torvalds 			continue;
122*1da177e4SLinus Torvalds 		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
123*1da177e4SLinus Torvalds 		irq_desc[i].handler = &pyxis_irq_type;
124*1da177e4SLinus Torvalds 	}
125*1da177e4SLinus Torvalds 
126*1da177e4SLinus Torvalds 	setup_irq(16+7, &isa_cascade_irqaction);
127*1da177e4SLinus Torvalds }
128