port enough sendpoint support for DSM-G600 from D-Link 2.4.21-pre4
[linux-2.4.git] / arch / ppc / platforms / cpc700_pic.c
1 /*
2  * arch/ppc/platforms/cpc700_pic.c
3  *
4  * Interrupt controller support for IBM Spruce
5  *
6  * Authors: Mark Greer, Matt Porter, and Johnnie Peters
7  *          mgreer@mvista.com
8  *          mporter@mvista.com
9  *          jpeters@mvista.com
10  *
11  * 2001-2002 (c) MontaVista, Software, Inc.  This file is licensed under
12  * the terms of the GNU General Public License version 2.  This program
13  * is licensed "as is" without any warranty of any kind, whether express
14  * or implied.
15  */
16
17 #include <linux/stddef.h>
18 #include <linux/init.h>
19 #include <linux/sched.h>
20 #include <linux/signal.h>
21 #include <linux/irq.h>
22
23 #include <asm/io.h>
24 #include <asm/processor.h>
25 #include <asm/system.h>
26 #include <asm/irq.h>
27
28 #include "cpc700.h"
29
30 static void
31 cpc700_unmask_irq(unsigned int irq)
32 {
33         unsigned int tr_bits;
34
35         /*
36          * IRQ 31 is largest IRQ supported.
37          * IRQs 17-19 are reserved.
38          */
39         if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
40                 tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
41
42                 if ((tr_bits & (1 << (31 - irq))) == 0) {
43                         /* level trigger interrupt, clear bit in status
44                          * register */
45                         CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
46                 }
47
48                 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
49                 ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
50
51                 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
52         }
53         return;
54 }
55
56 static void
57 cpc700_mask_irq(unsigned int irq)
58 {
59         /*
60          * IRQ 31 is largest IRQ supported.
61          * IRQs 17-19 are reserved.
62          */
63         if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
64                 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
65                 ppc_cached_irq_mask[0] &=
66                         ~CPC700_UIC_IRQ_BIT(irq);
67
68                 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
69         }
70         return;
71 }
72
73 static void
74 cpc700_mask_and_ack_irq(unsigned int irq)
75 {
76         u_int   bit;
77
78         /*
79          * IRQ 31 is largest IRQ supported.
80          * IRQs 17-19 are reserved.
81          */
82         if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
83                 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
84                 bit = CPC700_UIC_IRQ_BIT(irq);
85
86                 ppc_cached_irq_mask[0] &= ~bit;
87                 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
88                 CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
89         }
90         return;
91 }
92
93 static struct hw_interrupt_type cpc700_pic = {
94         "CPC700 PIC",
95         NULL,
96         NULL,
97         cpc700_unmask_irq,
98         cpc700_mask_irq,
99         cpc700_mask_and_ack_irq,
100         NULL,
101         NULL
102 };
103
104 __init static void
105 cpc700_pic_init_irq(unsigned int irq)
106 {
107         unsigned int tmp;
108
109         /* Set interrupt sense */
110         tmp = CPC700_IN_32(CPC700_UIC_UICTR);
111         if (cpc700_irq_assigns[irq][0] == 0) {
112                 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
113         } else {
114                 tmp |= CPC700_UIC_IRQ_BIT(irq);
115         }
116         CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
117
118         /* Set interrupt polarity */
119         tmp = CPC700_IN_32(CPC700_UIC_UICPR);
120         if (cpc700_irq_assigns[irq][1]) {
121                 tmp |= CPC700_UIC_IRQ_BIT(irq);
122         } else {
123                 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
124         }
125         CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
126
127         /* Set interrupt critical */
128         tmp = CPC700_IN_32(CPC700_UIC_UICCR);
129         tmp |= CPC700_UIC_IRQ_BIT(irq);
130         CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
131
132         return;
133 }
134
135 __init void
136 cpc700_init_IRQ(void)
137 {
138         int i;
139
140         ppc_cached_irq_mask[0] = 0;
141         CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000);    /* Disable all irq's */
142         CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff);    /* Clear cur intrs */
143         CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff);    /* Gen INT not MCP */
144         CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000);    /* Active low */
145         CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000);    /* Level Sensitive */
146         CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
147                                                         /* IRQ 0 is highest */
148
149         for (i = 0; i < 17; i++) {
150                 irq_desc[i].handler = &cpc700_pic;
151                 cpc700_pic_init_irq(i);
152         }
153
154         for (i = 20; i < 32; i++) {
155                 irq_desc[i].handler = &cpc700_pic;
156                 cpc700_pic_init_irq(i);
157         }
158
159         return;
160 }
161
162
163
164 /*
165  * Find the highest IRQ that generating an interrupt, if any.
166  */
167 int
168 cpc700_get_irq(struct pt_regs *regs)
169 {
170         int irq = 0;
171         u_int irq_status, irq_test = 1;
172
173         irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
174
175         do
176         {
177                 if (irq_status & irq_test)
178                         break;
179                 irq++;
180                 irq_test <<= 1;
181         } while (irq < NR_IRQS);
182
183
184         if (irq == NR_IRQS)
185             irq = 33;
186
187         return (31 - irq);
188 }