ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc / syslib / ppc8xx_pic.c
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 <asm/irq.h>
8 #include <asm/8xx_immap.h>
9 #include <asm/mpc8xx.h>
10 #include "ppc8xx_pic.h"
11
12 /* The 8xx internal interrupt controller.  It is usually
13  * the only interrupt controller.  Some boards, like the MBX and
14  * Sandpoint have the 8259 as a secondary controller.  Depending
15  * upon the processor type, the internal controller can have as
16  * few as 16 interrups or as many as 64.  We could use  the
17  * "clear_bit()" and "set_bit()" functions like other platforms,
18  * but they are overkill for us.
19  */
20
21 static void m8xx_mask_irq(unsigned int irq_nr)
22 {
23         int     bit, word;
24
25         bit = irq_nr & 0x1f;
26         word = irq_nr >> 5;
27
28         ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
29         ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
30                                                 ppc_cached_irq_mask[word];
31 }
32
33 static void m8xx_unmask_irq(unsigned int irq_nr)
34 {
35         int     bit, word;
36
37         bit = irq_nr & 0x1f;
38         word = irq_nr >> 5;
39
40         ppc_cached_irq_mask[word] |= (1 << (31-bit));
41         ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
42                                                 ppc_cached_irq_mask[word];
43 }
44
45 static void m8xx_end_irq(unsigned int irq_nr)
46 {
47         if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
48                         && irq_desc[irq_nr].action) {
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
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 #if 0
86 void
87 m8xx_do_IRQ(struct pt_regs *regs,
88            int            cpu)
89 {
90         int irq;
91         unsigned long bits = 0;
92
93         /* For MPC8xx, read the SIVEC register and shift the bits down
94          * to get the irq number.         */
95         bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
96         irq = bits >> 26;
97 #if 0
98         irq += ppc8xx_pic.irq_offset;
99 #endif
100         bits = 1UL << irq;
101
102         if (irq < 0) {
103                 printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
104                        irq, regs->nip);
105                 ppc_spurious_interrupts++;
106         }
107         else {
108                 ppc_irq_dispatch_handler( regs, irq );
109         }
110
111 }
112 #endif
113
114
115 /*
116  * We either return a valid interrupt or -1 if there is nothing pending
117  */
118 int
119 m8xx_get_irq(struct pt_regs *regs)
120 {
121         int irq;
122
123         /* For MPC8xx, read the SIVEC register and shift the bits down
124          * to get the irq number.
125          */
126         irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26;
127
128         /*
129          * When we read the sivec without an interrupt to process, we will
130          * get back SIU_LEVEL7.  In this case, return -1
131          */
132         if (irq == SIU_LEVEL7)
133                 return -1;
134
135         return irq;
136 }
137
138 /* The MBX is the only 8xx board that uses the 8259.
139 */
140 #if defined(CONFIG_MBX) && defined(CONFIG_PCI)
141 void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
142 {
143         int bits, irq;
144
145         /* A bug in the QSpan chip causes it to give us 0xff always
146          * when doing a character read.  So read 32 bits and shift.
147          * This doesn't seem to return useful values anyway, but
148          * read it to make sure things are acked.
149          * -- Cort
150          */
151         irq = (inl(0x508) >> 24)&0xff;
152         if ( irq != 0xff ) printk("iack %d\n", irq);
153
154         outb(0x0C, 0x20);
155         irq = inb(0x20) & 7;
156         if (irq == 2)
157         {
158                 outb(0x0C, 0xA0);
159                 irq = inb(0xA0);
160                 irq = (irq&7) + 8;
161         }
162         bits = 1UL << irq;
163         irq += i8259_pic.irq_offset;
164         ppc_irq_dispatch_handler( regs, irq );
165 }
166 #endif
167
168 /* Only the MBX uses the external 8259.  This allows us to catch standard
169  * drivers that may mess up the internal interrupt controllers, and also
170  * allow them to run without modification on the MBX.
171  */
172 int request_irq(unsigned int irq,
173         irqreturn_t (*handler)(int, void *, struct pt_regs *),
174         unsigned long irqflags, const char * devname, void *dev_id)
175 {
176
177 #if defined(CONFIG_MBX) && defined(CONFIG_PCI)
178         irq += i8259_pic.irq_offset;
179         return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
180 #else
181         /*
182          * Handle other "well-known" interrupts, but panic on unknown ones.
183          */
184         switch (irq) {
185 #ifdef  IDE0_INTERRUPT
186                 case IDE0_INTERRUPT:    /* IDE0 */
187                         return (request_8xxirq(irq, handler, irqflags, devname,
188                                                 dev_id));
189 #endif
190 #ifdef  IDE1_INTERRUPT
191                 case IDE1_INTERRUPT:    /* IDE1 */
192                         return (request_8xxirq(irq, handler, irqflags, devname,
193                                                 dev_id));
194 #endif
195         default:                        /* unknown IRQ -> panic */
196                 panic("request_irq");
197         }
198 #endif
199 }
200
201 EXPORT_SYMBOL(request_irq);