aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/syslib/ppc8xx_pic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/syslib/ppc8xx_pic.c')
-rw-r--r--arch/ppc/syslib/ppc8xx_pic.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/arch/ppc/syslib/ppc8xx_pic.c b/arch/ppc/syslib/ppc8xx_pic.c
new file mode 100644
index 000000000000..d3b01c6c97de
--- /dev/null
+++ b/arch/ppc/syslib/ppc8xx_pic.c
@@ -0,0 +1,130 @@
1#include <linux/config.h>
2#include <linux/module.h>
3#include <linux/stddef.h>
4#include <linux/init.h>
5#include <linux/sched.h>
6#include <linux/signal.h>
7#include <linux/interrupt.h>
8#include <asm/irq.h>
9#include <asm/8xx_immap.h>
10#include <asm/mpc8xx.h>
11#include "ppc8xx_pic.h"
12
13extern int cpm_get_irq(struct pt_regs *regs);
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
24static 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 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
33 ppc_cached_irq_mask[word];
34}
35
36static void m8xx_unmask_irq(unsigned int irq_nr)
37{
38 int bit, word;
39
40 bit = irq_nr & 0x1f;
41 word = irq_nr >> 5;
42
43 ppc_cached_irq_mask[word] |= (1 << (31-bit));
44 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
45 ppc_cached_irq_mask[word];
46}
47
48static void m8xx_end_irq(unsigned int irq_nr)
49{
50 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
51 && irq_desc[irq_nr].action) {
52 int bit, word;
53
54 bit = irq_nr & 0x1f;
55 word = irq_nr >> 5;
56
57 ppc_cached_irq_mask[word] |= (1 << (31-bit));
58 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
59 ppc_cached_irq_mask[word];
60 }
61}
62
63
64static void m8xx_mask_and_ack(unsigned int irq_nr)
65{
66 int bit, word;
67
68 bit = irq_nr & 0x1f;
69 word = irq_nr >> 5;
70
71 ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
72 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
73 ppc_cached_irq_mask[word];
74 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
75}
76
77struct hw_interrupt_type ppc8xx_pic = {
78 .typename = " 8xx SIU ",
79 .enable = m8xx_unmask_irq,
80 .disable = m8xx_mask_irq,
81 .ack = m8xx_mask_and_ack,
82 .end = m8xx_end_irq,
83};
84
85/*
86 * We either return a valid interrupt or -1 if there is nothing pending
87 */
88int
89m8xx_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_MBX) && defined(CONFIG_PCI)
119/* Only the MBX uses the external 8259. This allows us to catch standard
120 * drivers that may mess up the internal interrupt controllers, and also
121 * allow them to run without modification on the MBX.
122 */
123void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
124{
125 /* This interrupt handler never actually gets called. It is
126 * installed only to unmask the 8259 cascade interrupt in the SIU
127 * and to make the 8259 cascade interrupt visible in /proc/interrupts.
128 */
129}
130#endif /* CONFIG_PCI */