1 #include <linux/config.h>
2 #include <linux/stddef.h>
3 #include <linux/init.h>
4 #include <linux/sched.h>
5 #include <linux/signal.h>
6 #include <asm/irq.h>
7 #include <asm/8xx_immap.h>
8 #include <asm/mpc8xx.h>
9 #include "ppc8xx_pic.h"
10 
11 extern int cpm_get_irq(struct pt_regs *regs);
12 
13 /* The 8xx internal interrupt controller.  It is usually
14  * the only interrupt controller.  Some boards, like the MBX and
15  * Sandpoint have the 8259 as a secondary controller.  Depending
16  * upon the processor type, the internal controller can have as
17  * few as 16 interrups or as many as 64.  We could use  the
18  * "clear_bit()" and "set_bit()" functions like other platforms,
19  * but they are overkill for us.
20  */
21 
m8xx_mask_irq(unsigned int irq_nr)22 static void m8xx_mask_irq(unsigned int irq_nr)
23 {
24 	int	bit, word;
25 
26 	bit = irq_nr & 0x1f;
27 	word = irq_nr >> 5;
28 
29 	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
30 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
31 						ppc_cached_irq_mask[word];
32 }
33 
m8xx_unmask_irq(unsigned int irq_nr)34 static void m8xx_unmask_irq(unsigned int irq_nr)
35 {
36 	int	bit, word;
37 
38 	bit = irq_nr & 0x1f;
39 	word = irq_nr >> 5;
40 
41 	ppc_cached_irq_mask[word] |= (1 << (31-bit));
42 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
43 						ppc_cached_irq_mask[word];
44 }
45 
m8xx_end_irq(unsigned int irq_nr)46 static void m8xx_end_irq(unsigned int irq_nr)
47 {
48 	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
49 		int bit, word;
50 
51 		bit = irq_nr & 0x1f;
52 		word = irq_nr >> 5;
53 
54 		ppc_cached_irq_mask[word] |= (1 << (31-bit));
55 		((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
56 			ppc_cached_irq_mask[word];
57 	}
58 }
59 
60 
m8xx_mask_and_ack(unsigned int irq_nr)61 static void m8xx_mask_and_ack(unsigned int irq_nr)
62 {
63 	int	bit, word;
64 
65 	bit = irq_nr & 0x1f;
66 	word = irq_nr >> 5;
67 
68 	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
69 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
70 						ppc_cached_irq_mask[word];
71 	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
72 }
73 
74 struct hw_interrupt_type ppc8xx_pic = {
75 	" 8xx SIU  ",
76 	NULL,
77 	NULL,
78 	m8xx_unmask_irq,
79 	m8xx_mask_irq,
80 	m8xx_mask_and_ack,
81 	m8xx_end_irq,
82 	0
83 };
84 
85 /*
86  * We either return a valid interrupt or -1 if there is nothing pending
87  */
88 int
m8xx_get_irq(struct pt_regs * regs)89 m8xx_get_irq(struct pt_regs *regs)
90 {
91 	int irq;
92 
93 	/* For MPC8xx, read the SIVEC register and shift the bits down
94 	 * to get the irq number.
95 	 */
96 	irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26;
97 
98 	/*
99 	 * When we read the sivec without an interrupt to process, we will
100 	 * get back SIU_LEVEL7.  In this case, return -1
101 	 */
102         if (irq == CPM_INTERRUPT)
103         	irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
104 #if defined(CONFIG_PCI)
105 	else if (irq == ISA_BRIDGE_INT) {
106 		int isa_irq;
107 
108 		if ((isa_irq = i8259_poll(regs)) >= 0)
109 			irq = I8259_IRQ_OFFSET + isa_irq;
110 	}
111 #endif	/* CONFIG_PCI */
112 	else if (irq == SIU_LEVEL7)
113 		irq = -1;
114 
115 	return irq;
116 }
117 
118 #if defined(CONFIG_PCI)
119 /* Handler for the MPC8xx SIU cascade interrupt for the 8259 interrupt
120  * controller
121  */
mbx_i8259_action(int irq,void * dev_id,struct pt_regs * regs)122 void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
123 {
124 	/* This interrupt handler never actually gets called.  It is
125 	 * installed only to unmask the 8259 cascade interrupt in the SIU
126 	 * and to make the 8259 cascade interrupt visible in /proc/interrupts.
127 	 */
128 }
129 #endif	/* CONFIG_PCI */
130