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