sync hh.org
[hh.org.git] / arch / ppc / syslib / mpc52xx_pic.c
blobaf35a316544a1a3308ce1cccff538a806fb066fb
1 /*
2 * Programmable Interrupt Controller functions for the Freescale MPC52xx
3 * embedded CPU.
5 *
6 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
8 * Based on (well, mostly copied from) the code from the 2.4 kernel by
9 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
11 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
12 * Copyright (C) 2003 Montavista Software, Inc
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.
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>
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>
34 static struct mpc52xx_intr __iomem *intr;
35 static struct mpc52xx_sdma __iomem *sdma;
37 static void
38 mpc52xx_ic_disable(unsigned int irq)
40 u32 val;
42 if (irq == MPC52xx_IRQ0) {
43 val = in_be32(&intr->ctrl);
44 val &= ~(1 << 11);
45 out_be32(&intr->ctrl, val);
47 else if (irq < MPC52xx_IRQ1) {
48 BUG();
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);
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);
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);
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);
72 static void
73 mpc52xx_ic_enable(unsigned int irq)
75 u32 val;
77 if (irq == MPC52xx_IRQ0) {
78 val = in_be32(&intr->ctrl);
79 val |= 1 << 11;
80 out_be32(&intr->ctrl, val);
82 else if (irq < MPC52xx_IRQ1) {
83 BUG();
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);
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);
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);
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);
107 static void
108 mpc52xx_ic_ack(unsigned int irq)
110 u32 val;
113 * Only some irqs are reset here, others in interrupting hardware.
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));
148 break;
152 static void
153 mpc52xx_ic_disable_and_ack(unsigned int irq)
155 mpc52xx_ic_disable(irq);
156 mpc52xx_ic_ack(irq);
159 static void
160 mpc52xx_ic_end(unsigned int irq)
162 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
163 mpc52xx_ic_enable(irq);
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,
174 void __init
175 mpc52xx_init_irq(void)
177 int i;
178 u32 intr_ctrl;
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);
184 if ((intr==NULL) || (sdma==NULL))
185 panic("Can't ioremap PIC/SDMA register for init_irq !");
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);
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);
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;
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;
223 mpc52xx_get_irq(void)
225 u32 status;
226 int irq = -1;
228 status = in_be32(&intr->enc_status);
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;
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;
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;
249 else
250 irq += MPC52xx_PERP_IRQ_BASE;
253 return irq;