blob: 4c4497e62517daec2c0cf0b9778c176aa1e042f3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
36static struct mpc52xx_intr __iomem *intr;
37static struct mpc52xx_sdma __iomem *sdma;
38
39static void
40mpc52xx_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
74static void
75mpc52xx_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
109static void
110mpc52xx_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
154static void
155mpc52xx_ic_disable_and_ack(unsigned int irq)
156{
157 mpc52xx_ic_disable(irq);
158 mpc52xx_ic_ack(irq);
159}
160
161static void
162mpc52xx_ic_end(unsigned int irq)
163{
164 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
165 mpc52xx_ic_enable(irq);
166}
167
168static struct hw_interrupt_type mpc52xx_ic = {
169 .typename = " MPC52xx ",
170 .enable = mpc52xx_ic_enable,
171 .disable = mpc52xx_ic_disable,
172 .ack = mpc52xx_ic_disable_and_ack,
173 .end = mpc52xx_ic_end,
174};
175
176void __init
177mpc52xx_init_irq(void)
178{
179 int i;
180 u32 intr_ctrl;
181
182 /* Remap the necessary zones */
183 intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
184 sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE);
185
186 if ((intr==NULL) || (sdma==NULL))
187 panic("Can't ioremap PIC/SDMA register for init_irq !");
188
189 /* Disable all interrupt sources. */
190 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
191 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
192 out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
193 out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
194 intr_ctrl = in_be32(&intr->ctrl);
195 intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */
196 intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
197 0x00001000 | /* MEE master external enable */
198 0x00000000 | /* 0 means disable IRQ 0-3 */
199 0x00000001; /* CEb route critical normally */
200 out_be32(&intr->ctrl, intr_ctrl);
201
202 /* Zero a bunch of the priority settings. */
203 out_be32(&intr->per_pri1, 0);
204 out_be32(&intr->per_pri2, 0);
205 out_be32(&intr->per_pri3, 0);
206 out_be32(&intr->main_pri1, 0);
207 out_be32(&intr->main_pri2, 0);
208
209 /* Initialize irq_desc[i].handler's with mpc52xx_ic. */
210 for (i = 0; i < NR_IRQS; i++) {
211 irq_desc[i].handler = &mpc52xx_ic;
212 irq_desc[i].status = IRQ_LEVEL;
213 }
214
215 #define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03)
216 for (i=0 ; i<4 ; i++) {
217 int mode;
218 mode = IRQn_MODE(intr_ctrl,i);
219 if ((mode == 0x1) || (mode == 0x2))
220 irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0;
221 }
222}
223
224int
225mpc52xx_get_irq(struct pt_regs *regs)
226{
227 u32 status;
228 int irq = -1;
229
230 status = in_be32(&intr->enc_status);
231
232 if (status & 0x00000400) { /* critical */
233 irq = (status >> 8) & 0x3;
234 if (irq == 2) /* high priority peripheral */
235 goto peripheral;
236 irq += MPC52xx_CRIT_IRQ_BASE;
237 }
238 else if (status & 0x00200000) { /* main */
239 irq = (status >> 16) & 0x1f;
240 if (irq == 4) /* low priority peripheral */
241 goto peripheral;
242 irq += MPC52xx_MAIN_IRQ_BASE;
243 }
244 else if (status & 0x20000000) { /* peripheral */
245peripheral:
246 irq = (status >> 24) & 0x1f;
247 if (irq == 0) { /* bestcomm */
248 status = in_be32(&sdma->IntPend);
249 irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1;
250 }
251 else
252 irq += MPC52xx_PERP_IRQ_BASE;
253 }
254
255 return irq;
256}
257