ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc / platforms / adir_pic.c
1 /*
2  * arch/ppc/platforms/adir_pic.c
3  *
4  * Interrupt controller support for SBS Adirondack
5  *
6  * By Michael Sokolov <msokolov@ivan.Harhan.ORG>
7  * based on the K2 and SCM versions by Matt Porter <mporter@mvista.com>
8  */
9
10 #include <linux/stddef.h>
11 #include <linux/init.h>
12 #include <linux/sched.h>
13 #include <linux/pci.h>
14 #include <linux/irq.h>
15
16 #include <asm/io.h>
17 #include <asm/i8259.h>
18 #include "adir.h"
19
20 static void adir_onboard_pic_enable(unsigned int irq);
21 static void adir_onboard_pic_disable(unsigned int irq);
22
23 static void
24 no_action(int cpl, void *dev_id, struct pt_regs *regs)
25 {
26 }
27
28 __init static void
29 adir_onboard_pic_init(void)
30 {
31         volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
32
33         /* Disable all Adirondack onboard interrupts */
34         out_be16(maskreg, 0xFFFF);
35 }
36
37 static int
38 adir_onboard_pic_get_irq(void)
39 {
40         volatile u_short *statreg = (volatile u_short *) ADIR_PROCA_INT_STAT;
41         int irq;
42         u_short int_status, int_test;
43
44         int_status = in_be16(statreg);
45         for (irq = 0, int_test = 1; irq < 16; irq++, int_test <<= 1) {
46                 if (int_status & int_test)
47                         break;
48         }
49
50         if (irq == 16)
51                 return -1;
52
53         return (irq+16);
54 }
55
56 static void
57 adir_onboard_pic_enable(unsigned int irq)
58 {
59         volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
60
61         /* Change irq to Adirondack onboard native value */
62         irq -= 16;
63
64         /* Enable requested irq number */
65         out_be16(maskreg, in_be16(maskreg) & ~(1 << irq));
66 }
67
68 static void
69 adir_onboard_pic_disable(unsigned int irq)
70 {
71         volatile u_short *maskreg = (volatile u_short *) ADIR_PROCA_INT_MASK;
72
73         /* Change irq to Adirondack onboard native value */
74         irq -= 16;
75
76         /* Disable requested irq number */
77         out_be16(maskreg, in_be16(maskreg) | (1 << irq));
78 }
79
80 static struct hw_interrupt_type adir_onboard_pic = {
81         " ADIR PIC ",
82         NULL,
83         NULL,
84         adir_onboard_pic_enable,                /* unmask */
85         adir_onboard_pic_disable,               /* mask */
86         adir_onboard_pic_disable,               /* mask and ack */
87         NULL,
88         NULL
89 };
90
91 /*
92  * Linux interrupt values are assigned as follows:
93  *
94  *      0-15            VT82C686 8259 interrupts
95  *      16-31           Adirondack CPLD interrupts
96  */
97 __init void
98 adir_init_IRQ(void)
99 {
100         int     i;
101
102         /* Initialize the cascaded 8259's on the VT82C686 */
103         for (i=0; i<16; i++)
104                 irq_desc[i].handler = &i8259_pic;
105         i8259_init(NULL);
106
107         /* Initialize Adirondack CPLD PIC and enable 8259 interrupt cascade */
108         for (i=16; i<32; i++)
109                 irq_desc[i].handler = &adir_onboard_pic;
110         adir_onboard_pic_init();
111
112         /* Enable 8259 interrupt cascade */
113         request_irq(ADIR_IRQ_VT82C686_INTR,
114                         no_action,
115                         SA_INTERRUPT,
116                         "82c59 primary cascade",
117                         NULL);
118 }
119
120 int
121 adir_get_irq(struct pt_regs *regs)
122 {
123         int     irq;
124
125         if ((irq = adir_onboard_pic_get_irq()) < 0)
126                 return irq;
127
128         if (irq == ADIR_IRQ_VT82C686_INTR)
129                 irq = i8259_irq(regs);
130
131         return irq;
132 }