diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/syslib/mpc52xx_pic.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/syslib/mpc52xx_pic.c')
-rw-r--r-- | arch/ppc/syslib/mpc52xx_pic.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c new file mode 100644 index 000000000000..4c4497e62517 --- /dev/null +++ b/arch/ppc/syslib/mpc52xx_pic.c | |||
@@ -0,0 +1,257 @@ | |||
1 | /* | ||
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 | |||
36 | static struct mpc52xx_intr __iomem *intr; | ||
37 | static struct mpc52xx_sdma __iomem *sdma; | ||
38 | |||
39 | static void | ||
40 | mpc52xx_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 | |||
74 | static void | ||
75 | mpc52xx_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 | |||
109 | static void | ||
110 | mpc52xx_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 | |||
154 | static void | ||
155 | mpc52xx_ic_disable_and_ack(unsigned int irq) | ||
156 | { | ||
157 | mpc52xx_ic_disable(irq); | ||
158 | mpc52xx_ic_ack(irq); | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | mpc52xx_ic_end(unsigned int irq) | ||
163 | { | ||
164 | if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) | ||
165 | mpc52xx_ic_enable(irq); | ||
166 | } | ||
167 | |||
168 | static 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 | |||
176 | void __init | ||
177 | mpc52xx_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 | |||
224 | int | ||
225 | mpc52xx_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 */ | ||
245 | peripheral: | ||
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 | |||