blob: 3e6f51a61d468c79e18f6046f93d6bd7ca4b6f50 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#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>
Marcelo Tosattie37b0c92005-10-28 17:46:10 -07009#include <asm/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <asm/8xx_immap.h>
11#include <asm/mpc8xx.h>
12#include "ppc8xx_pic.h"
13
14extern int cpm_get_irq(struct pt_regs *regs);
15
16/* The 8xx internal interrupt controller. It is usually
17 * the only interrupt controller. Some boards, like the MBX and
18 * Sandpoint have the 8259 as a secondary controller. Depending
19 * upon the processor type, the internal controller can have as
20 * few as 16 interrups or as many as 64. We could use the
21 * "clear_bit()" and "set_bit()" functions like other platforms,
22 * but they are overkill for us.
23 */
24
25static void m8xx_mask_irq(unsigned int irq_nr)
26{
27 int bit, word;
28
29 bit = irq_nr & 0x1f;
30 word = irq_nr >> 5;
31
32 ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
Marcelo Tosattie37b0c92005-10-28 17:46:10 -070033 out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070034}
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));
Marcelo Tosattie37b0c92005-10-28 17:46:10 -070044 out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045}
46
47static void m8xx_end_irq(unsigned int irq_nr)
48{
49 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
50 && irq_desc[irq_nr].action) {
51 int bit, word;
52
53 bit = irq_nr & 0x1f;
54 word = irq_nr >> 5;
55
56 ppc_cached_irq_mask[word] |= (1 << (31-bit));
Marcelo Tosattie37b0c92005-10-28 17:46:10 -070057 out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058 }
59}
60
61
62static void m8xx_mask_and_ack(unsigned int irq_nr)
63{
64 int bit, word;
65
66 bit = irq_nr & 0x1f;
67 word = irq_nr >> 5;
68
69 ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
Marcelo Tosattie37b0c92005-10-28 17:46:10 -070070 out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask, ppc_cached_irq_mask[word]);
71 out_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend, 1 << (31-bit));
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
73
74struct hw_interrupt_type ppc8xx_pic = {
75 .typename = " 8xx SIU ",
76 .enable = m8xx_unmask_irq,
77 .disable = m8xx_mask_irq,
78 .ack = m8xx_mask_and_ack,
79 .end = m8xx_end_irq,
80};
81
82/*
83 * We either return a valid interrupt or -1 if there is nothing pending
84 */
85int
86m8xx_get_irq(struct pt_regs *regs)
87{
88 int irq;
89
90 /* For MPC8xx, read the SIVEC register and shift the bits down
91 * to get the irq number.
92 */
Marcelo Tosattie37b0c92005-10-28 17:46:10 -070093 irq = in_be32(&((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec) >> 26;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
95 /*
96 * When we read the sivec without an interrupt to process, we will
97 * get back SIU_LEVEL7. In this case, return -1
98 */
99 if (irq == CPM_INTERRUPT)
100 irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
101#if defined(CONFIG_PCI)
102 else if (irq == ISA_BRIDGE_INT) {
103 int isa_irq;
104
105 if ((isa_irq = i8259_poll(regs)) >= 0)
106 irq = I8259_IRQ_OFFSET + isa_irq;
107 }
108#endif /* CONFIG_PCI */
109 else if (irq == SIU_LEVEL7)
110 irq = -1;
111
112 return irq;
113}
114
115#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
116/* Only the MBX uses the external 8259. This allows us to catch standard
117 * drivers that may mess up the internal interrupt controllers, and also
118 * allow them to run without modification on the MBX.
119 */
120void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
121{
122 /* This interrupt handler never actually gets called. It is
123 * installed only to unmask the 8259 cascade interrupt in the SIU
124 * and to make the 8259 cascade interrupt visible in /proc/interrupts.
125 */
126}
127#endif /* CONFIG_PCI */