This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / ppc / syslib / mpc52xx_pic.c
1 /*
2  * arch/ppc/syslib/mpc52xx_pic.c
3  *
4  * Programmable Interrupt Controller functions for the Freescale MPC52xx 
5  * embedded CPU.
6  *
7  * 
8  * Maintainer : Sylvain Munaut <tnt@246tNt.com>
9  *
10  * Based on (well, mostly copied from) the code from the 2.4 kernel by
11  * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
12  * 
13  * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
14  * Copyright (C) 2003 Montavista Software, Inc
15  * 
16  * This file is licensed under the terms of the GNU General Public License
17  * version 2. This program is licensed "as is" without any warranty of any
18  * kind, whether express or implied.
19  */
20
21 #include <linux/stddef.h>
22 #include <linux/init.h>
23 #include <linux/sched.h>
24 #include <linux/signal.h>
25 #include <linux/stddef.h>
26 #include <linux/delay.h>
27 #include <linux/irq.h>
28
29 #include <asm/io.h>
30 #include <asm/processor.h>
31 #include <asm/system.h>
32 #include <asm/irq.h>
33 #include <asm/mpc52xx.h>
34
35
36 static struct mpc52xx_intr *intr;
37 static struct mpc52xx_sdma *sdma;
38
39 static void
40 mpc52xx_ic_disable(unsigned int irq)
41 {
42         u32 val;
43
44         if (irq == MPC52xx_IRQ0) {
45                 val = in_be32(&intr->ctrl);
46                 val &= ~(1 << 11);
47                 out_be32(&intr->ctrl, val);
48         }
49         else if (irq < MPC52xx_IRQ1) {
50                 BUG();
51         }
52         else if (irq <= MPC52xx_IRQ3) {
53                 val = in_be32(&intr->ctrl);
54                 val &= ~(1 << (10 - (irq - MPC52xx_IRQ1)));
55                 out_be32(&intr->ctrl, val);
56         }
57         else if (irq < MPC52xx_SDMA_IRQ_BASE) {
58                 val = in_be32(&intr->main_mask);
59                 val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE));
60                 out_be32(&intr->main_mask, val);
61         }
62         else if (irq < MPC52xx_PERP_IRQ_BASE) {
63                 val = in_be32(&sdma->IntMask);
64                 val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE);
65                 out_be32(&sdma->IntMask, val);
66         }
67         else {
68                 val = in_be32(&intr->per_mask);
69                 val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE));
70                 out_be32(&intr->per_mask, val);
71         }
72 }
73
74 static void
75 mpc52xx_ic_enable(unsigned int irq)
76 {
77         u32 val;
78
79         if (irq == MPC52xx_IRQ0) {
80                 val = in_be32(&intr->ctrl);
81                 val |= 1 << 11;
82                 out_be32(&intr->ctrl, val);
83         }
84         else if (irq < MPC52xx_IRQ1) {
85                 BUG();
86         }
87         else if (irq <= MPC52xx_IRQ3) {
88                 val = in_be32(&intr->ctrl);
89                 val |= 1 << (10 - (irq - MPC52xx_IRQ1));
90                 out_be32(&intr->ctrl, val);
91         }
92         else if (irq < MPC52xx_SDMA_IRQ_BASE) {
93                 val = in_be32(&intr->main_mask);
94                 val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)));
95                 out_be32(&intr->main_mask, val);
96         }
97         else if (irq < MPC52xx_PERP_IRQ_BASE) {
98                 val = in_be32(&sdma->IntMask);
99                 val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE));
100                 out_be32(&sdma->IntMask, val);
101         }
102         else {
103                 val = in_be32(&intr->per_mask);
104                 val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)));
105                 out_be32(&intr->per_mask, val);
106         }
107 }
108
109 static void
110 mpc52xx_ic_ack(unsigned int irq)
111 {
112         u32 val;
113
114         /*
115          * Only some irqs are reset here, others in interrupting hardware.
116          */
117                         
118         switch (irq) {
119         case MPC52xx_IRQ0:
120                 val = in_be32(&intr->ctrl);
121                 val |= 0x08000000;
122                 out_be32(&intr->ctrl, val);
123                 break;
124         case MPC52xx_CCS_IRQ:
125                 val = in_be32(&intr->enc_status);
126                 val |= 0x00000400;
127                 out_be32(&intr->enc_status, val);
128                 break;
129         case MPC52xx_IRQ1:
130                 val = in_be32(&intr->ctrl);
131                 val |= 0x04000000;
132                 out_be32(&intr->ctrl, val);
133                 break;
134         case MPC52xx_IRQ2:
135                 val = in_be32(&intr->ctrl);
136                 val |= 0x02000000;
137                 out_be32(&intr->ctrl, val);
138                 break;
139         case MPC52xx_IRQ3:
140                 val = in_be32(&intr->ctrl);
141                 val |= 0x01000000;
142                 out_be32(&intr->ctrl, val);
143                 break;
144         default:
145                 if (irq >= MPC52xx_SDMA_IRQ_BASE
146                     && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) {
147                         out_be32(&sdma->IntPend,
148                                  1 << (irq - MPC52xx_SDMA_IRQ_BASE));
149                 }
150                 break;
151         }
152 }
153
154 static void
155 mpc52xx_ic_disable_and_ack(unsigned int irq)
156 {
157         mpc52xx_ic_disable(irq);
158         mpc52xx_ic_ack(irq);
159 }
160
161 static void
162 mpc52xx_ic_end(unsigned int irq)
163 {
164         if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
165                 mpc52xx_ic_enable(irq);
166 }
167
168 static struct hw_interrupt_type mpc52xx_ic = {
169         "MPC52xx",
170         NULL,                           /* startup(irq) */
171         NULL,                           /* shutdown(irq) */
172         mpc52xx_ic_enable,              /* enable(irq) */
173         mpc52xx_ic_disable,             /* disable(irq) */
174         mpc52xx_ic_disable_and_ack,     /* disable_and_ack(irq) */
175         mpc52xx_ic_end,                 /* end(irq) */
176         0                               /* set_affinity(irq, cpumask) SMP. */
177 };
178
179 void __init
180 mpc52xx_init_irq(void)
181 {
182         int i;
183
184         /* Remap the necessary zones */
185         intr = (struct mpc52xx_intr *)
186                 ioremap(MPC52xx_INTR, sizeof(struct mpc52xx_intr));
187         sdma = (struct mpc52xx_sdma *)
188                 ioremap(MPC52xx_SDMA, sizeof(struct mpc52xx_sdma));
189         
190         if ((intr==NULL) || (sdma==NULL))
191                 panic("Can't ioremap PIC/SDMA register for init_irq !");
192
193         /* Disable all interrupt sources. */
194         out_be32(&sdma->IntPend, 0xffffffff);   /* 1 means clear pending */
195         out_be32(&sdma->IntMask, 0xffffffff);   /* 1 means disabled */
196         out_be32(&intr->per_mask, 0x7ffffc00);  /* 1 means disabled */
197         out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
198         out_be32(&intr->ctrl,
199                         0x0f000000 |    /* clear IRQ 0-3 */
200                         0x00c00000 |    /* IRQ0: level-sensitive, active low */
201                         0x00001000 |    /* MEE master external enable */
202                         0x00000000 |    /* 0 means disable IRQ 0-3 */
203                         0x00000001);    /* CEb route critical normally */
204
205         /* Zero a bunch of the priority settings.  */
206         out_be32(&intr->per_pri1, 0);
207         out_be32(&intr->per_pri2, 0);
208         out_be32(&intr->per_pri3, 0);
209         out_be32(&intr->main_pri1, 0);
210         out_be32(&intr->main_pri2, 0);
211
212         /* Initialize irq_desc[i].handler's with mpc52xx_ic. */
213         for (i = 0; i < NR_IRQS; i++) {
214                 irq_desc[i].handler = &mpc52xx_ic;
215                 irq_desc[i].status = IRQ_LEVEL;
216         }
217 }
218
219 int
220 mpc52xx_get_irq(struct pt_regs *regs)
221 {
222         u32 status;
223         int irq = -1;
224
225         status = in_be32(&intr->enc_status);
226
227         if (status & 0x00000400) {              /* critical */
228                 irq = (status >> 8) & 0x3;
229                 if (irq == 2)                   /* high priority peripheral */
230                         goto peripheral;
231                 irq += MPC52xx_CRIT_IRQ_BASE;
232         }
233         else if (status & 0x00200000) {         /* main */
234                 irq = (status >> 16) & 0x1f;
235                 if (irq == 4)                   /* low priority peripheral */
236                         goto peripheral;
237                 irq += MPC52xx_MAIN_IRQ_BASE;
238         }
239         else if (status & 0x20000000) {         /* peripheral */
240 peripheral:
241                 irq = (status >> 24) & 0x1f;
242                 if (irq == 0) {                 /* bestcomm */
243                         status = in_be32(&sdma->IntPend);
244                         irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1;
245                 }
246                 else
247                         irq += MPC52xx_PERP_IRQ_BASE;
248         }
249
250         return irq;
251 }
252