2 * arch/ppc/syslib/mpc52xx_pic.c
4 * Programmable Interrupt Controller functions for the Freescale MPC52xx
8 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
10 * Based on (well, mostly copied from) the code from the 2.4 kernel by
11 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
13 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
14 * Copyright (C) 2003 Montavista Software, Inc
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.
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>
30 #include <asm/processor.h>
31 #include <asm/system.h>
33 #include <asm/mpc52xx.h>
36 static struct mpc52xx_intr *intr;
37 static struct mpc52xx_sdma *sdma;
40 mpc52xx_ic_disable(unsigned int irq)
44 if (irq == MPC52xx_IRQ0) {
45 val = in_be32(&intr->ctrl);
47 out_be32(&intr->ctrl, val);
49 else if (irq < MPC52xx_IRQ1) {
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);
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);
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);
68 val = in_be32(&intr->per_mask);
69 val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE));
70 out_be32(&intr->per_mask, val);
75 mpc52xx_ic_enable(unsigned int irq)
79 if (irq == MPC52xx_IRQ0) {
80 val = in_be32(&intr->ctrl);
82 out_be32(&intr->ctrl, val);
84 else if (irq < MPC52xx_IRQ1) {
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);
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);
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);
103 val = in_be32(&intr->per_mask);
104 val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)));
105 out_be32(&intr->per_mask, val);
110 mpc52xx_ic_ack(unsigned int irq)
115 * Only some irqs are reset here, others in interrupting hardware.
120 val = in_be32(&intr->ctrl);
122 out_be32(&intr->ctrl, val);
124 case MPC52xx_CCS_IRQ:
125 val = in_be32(&intr->enc_status);
127 out_be32(&intr->enc_status, val);
130 val = in_be32(&intr->ctrl);
132 out_be32(&intr->ctrl, val);
135 val = in_be32(&intr->ctrl);
137 out_be32(&intr->ctrl, val);
140 val = in_be32(&intr->ctrl);
142 out_be32(&intr->ctrl, val);
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));
155 mpc52xx_ic_disable_and_ack(unsigned int irq)
157 mpc52xx_ic_disable(irq);
162 mpc52xx_ic_end(unsigned int irq)
164 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
165 mpc52xx_ic_enable(irq);
168 static struct hw_interrupt_type mpc52xx_ic = {
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. */
180 mpc52xx_init_irq(void)
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));
190 if ((intr==NULL) || (sdma==NULL))
191 panic("Can't ioremap PIC/SDMA register for init_irq !");
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 */
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);
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;
220 mpc52xx_get_irq(struct pt_regs *regs)
225 status = in_be32(&intr->enc_status);
227 if (status & 0x00000400) { /* critical */
228 irq = (status >> 8) & 0x3;
229 if (irq == 2) /* high priority peripheral */
231 irq += MPC52xx_CRIT_IRQ_BASE;
233 else if (status & 0x00200000) { /* main */
234 irq = (status >> 16) & 0x1f;
235 if (irq == 4) /* low priority peripheral */
237 irq += MPC52xx_MAIN_IRQ_BASE;
239 else if (status & 0x20000000) { /* 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;
247 irq += MPC52xx_PERP_IRQ_BASE;