blob: f58149c03b0fcbe9fe326878ff3a84256aaf18c4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * 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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/delay.h>
24#include <linux/irq.h>
25
26#include <asm/io.h>
27#include <asm/processor.h>
28#include <asm/system.h>
29#include <asm/irq.h>
30#include <asm/mpc52xx.h>
31
32
33static struct mpc52xx_intr __iomem *intr;
34static struct mpc52xx_sdma __iomem *sdma;
35
36static void
37mpc52xx_ic_disable(unsigned int irq)
38{
39 u32 val;
40
41 if (irq == MPC52xx_IRQ0) {
42 val = in_be32(&intr->ctrl);
43 val &= ~(1 << 11);
44 out_be32(&intr->ctrl, val);
45 }
46 else if (irq < MPC52xx_IRQ1) {
47 BUG();
48 }
49 else if (irq <= MPC52xx_IRQ3) {
50 val = in_be32(&intr->ctrl);
51 val &= ~(1 << (10 - (irq - MPC52xx_IRQ1)));
52 out_be32(&intr->ctrl, val);
53 }
54 else if (irq < MPC52xx_SDMA_IRQ_BASE) {
55 val = in_be32(&intr->main_mask);
56 val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE));
57 out_be32(&intr->main_mask, val);
58 }
59 else if (irq < MPC52xx_PERP_IRQ_BASE) {
60 val = in_be32(&sdma->IntMask);
61 val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE);
62 out_be32(&sdma->IntMask, val);
63 }
64 else {
65 val = in_be32(&intr->per_mask);
66 val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE));
67 out_be32(&intr->per_mask, val);
68 }
69}
70
71static void
72mpc52xx_ic_enable(unsigned int irq)
73{
74 u32 val;
75
76 if (irq == MPC52xx_IRQ0) {
77 val = in_be32(&intr->ctrl);
78 val |= 1 << 11;
79 out_be32(&intr->ctrl, val);
80 }
81 else if (irq < MPC52xx_IRQ1) {
82 BUG();
83 }
84 else if (irq <= MPC52xx_IRQ3) {
85 val = in_be32(&intr->ctrl);
86 val |= 1 << (10 - (irq - MPC52xx_IRQ1));
87 out_be32(&intr->ctrl, val);
88 }
89 else if (irq < MPC52xx_SDMA_IRQ_BASE) {
90 val = in_be32(&intr->main_mask);
91 val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)));
92 out_be32(&intr->main_mask, val);
93 }
94 else if (irq < MPC52xx_PERP_IRQ_BASE) {
95 val = in_be32(&sdma->IntMask);
96 val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE));
97 out_be32(&sdma->IntMask, val);
98 }
99 else {
100 val = in_be32(&intr->per_mask);
101 val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)));
102 out_be32(&intr->per_mask, val);
103 }
104}
105
106static void
107mpc52xx_ic_ack(unsigned int irq)
108{
109 u32 val;
110
111 /*
112 * Only some irqs are reset here, others in interrupting hardware.
113 */
114
115 switch (irq) {
116 case MPC52xx_IRQ0:
117 val = in_be32(&intr->ctrl);
118 val |= 0x08000000;
119 out_be32(&intr->ctrl, val);
120 break;
121 case MPC52xx_CCS_IRQ:
122 val = in_be32(&intr->enc_status);
123 val |= 0x00000400;
124 out_be32(&intr->enc_status, val);
125 break;
126 case MPC52xx_IRQ1:
127 val = in_be32(&intr->ctrl);
128 val |= 0x04000000;
129 out_be32(&intr->ctrl, val);
130 break;
131 case MPC52xx_IRQ2:
132 val = in_be32(&intr->ctrl);
133 val |= 0x02000000;
134 out_be32(&intr->ctrl, val);
135 break;
136 case MPC52xx_IRQ3:
137 val = in_be32(&intr->ctrl);
138 val |= 0x01000000;
139 out_be32(&intr->ctrl, val);
140 break;
141 default:
142 if (irq >= MPC52xx_SDMA_IRQ_BASE
143 && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) {
144 out_be32(&sdma->IntPend,
145 1 << (irq - MPC52xx_SDMA_IRQ_BASE));
146 }
147 break;
148 }
149}
150
151static void
152mpc52xx_ic_disable_and_ack(unsigned int irq)
153{
154 mpc52xx_ic_disable(irq);
155 mpc52xx_ic_ack(irq);
156}
157
158static void
159mpc52xx_ic_end(unsigned int irq)
160{
161 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
162 mpc52xx_ic_enable(irq);
163}
164
165static struct hw_interrupt_type mpc52xx_ic = {
166 .typename = " MPC52xx ",
167 .enable = mpc52xx_ic_enable,
168 .disable = mpc52xx_ic_disable,
169 .ack = mpc52xx_ic_disable_and_ack,
170 .end = mpc52xx_ic_end,
171};
172
173void __init
174mpc52xx_init_irq(void)
175{
176 int i;
177 u32 intr_ctrl;
178
179 /* Remap the necessary zones */
180 intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
181 sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE);
182
183 if ((intr==NULL) || (sdma==NULL))
184 panic("Can't ioremap PIC/SDMA register for init_irq !");
185
186 /* Disable all interrupt sources. */
187 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
188 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
189 out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
190 out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
191 intr_ctrl = in_be32(&intr->ctrl);
192 intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */
193 intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
194 0x00001000 | /* MEE master external enable */
195 0x00000000 | /* 0 means disable IRQ 0-3 */
196 0x00000001; /* CEb route critical normally */
197 out_be32(&intr->ctrl, intr_ctrl);
198
199 /* Zero a bunch of the priority settings. */
200 out_be32(&intr->per_pri1, 0);
201 out_be32(&intr->per_pri2, 0);
202 out_be32(&intr->per_pri3, 0);
203 out_be32(&intr->main_pri1, 0);
204 out_be32(&intr->main_pri2, 0);
205
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700206 /* Initialize irq_desc[i].chip's with mpc52xx_ic. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 for (i = 0; i < NR_IRQS; i++) {
Ingo Molnard1bef4e2006-06-29 02:24:36 -0700208 irq_desc[i].chip = &mpc52xx_ic;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 irq_desc[i].status = IRQ_LEVEL;
210 }
211
212 #define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03)
213 for (i=0 ; i<4 ; i++) {
214 int mode;
215 mode = IRQn_MODE(intr_ctrl,i);
216 if ((mode == 0x1) || (mode == 0x2))
217 irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0;
218 }
219}
220
221int
Al Viro39e3eb72006-10-09 12:48:42 +0100222mpc52xx_get_irq(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223{
224 u32 status;
225 int irq = -1;
226
227 status = in_be32(&intr->enc_status);
228
229 if (status & 0x00000400) { /* critical */
230 irq = (status >> 8) & 0x3;
231 if (irq == 2) /* high priority peripheral */
232 goto peripheral;
233 irq += MPC52xx_CRIT_IRQ_BASE;
234 }
235 else if (status & 0x00200000) { /* main */
236 irq = (status >> 16) & 0x1f;
237 if (irq == 4) /* low priority peripheral */
238 goto peripheral;
239 irq += MPC52xx_MAIN_IRQ_BASE;
240 }
241 else if (status & 0x20000000) { /* peripheral */
242peripheral:
243 irq = (status >> 24) & 0x1f;
244 if (irq == 0) { /* bestcomm */
245 status = in_be32(&sdma->IntPend);
246 irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1;
247 }
248 else
249 irq += MPC52xx_PERP_IRQ_BASE;
250 }
251
252 return irq;
253}
254