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