1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99#undef DEBUG
100
101#include <linux/interrupt.h>
102#include <linux/irq.h>
103#include <linux/of.h>
104#include <asm/io.h>
105#include <asm/prom.h>
106#include <asm/mpc52xx.h>
107
108
109#define MPC52xx_IRQ_L1_CRIT (0)
110#define MPC52xx_IRQ_L1_MAIN (1)
111#define MPC52xx_IRQ_L1_PERP (2)
112#define MPC52xx_IRQ_L1_SDMA (3)
113
114#define MPC52xx_IRQ_L1_OFFSET (6)
115#define MPC52xx_IRQ_L1_MASK (0x00c0)
116#define MPC52xx_IRQ_L2_MASK (0x003f)
117
118#define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0)
119
120
121
122static const struct of_device_id mpc52xx_pic_ids[] __initconst = {
123 { .compatible = "fsl,mpc5200-pic", },
124 { .compatible = "mpc5200-pic", },
125 {}
126};
127static const struct of_device_id mpc52xx_sdma_ids[] __initconst = {
128 { .compatible = "fsl,mpc5200-bestcomm", },
129 { .compatible = "mpc5200-bestcomm", },
130 {}
131};
132
133static struct mpc52xx_intr __iomem *intr;
134static struct mpc52xx_sdma __iomem *sdma;
135static struct irq_domain *mpc52xx_irqhost = NULL;
136
137static unsigned char mpc52xx_map_senses[4] = {
138 IRQ_TYPE_LEVEL_HIGH,
139 IRQ_TYPE_EDGE_RISING,
140 IRQ_TYPE_EDGE_FALLING,
141 IRQ_TYPE_LEVEL_LOW,
142};
143
144
145static inline void io_be_setbit(u32 __iomem *addr, int bitno)
146{
147 out_be32(addr, in_be32(addr) | (1 << bitno));
148}
149
150static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
151{
152 out_be32(addr, in_be32(addr) & ~(1 << bitno));
153}
154
155
156
157
158static void mpc52xx_extirq_mask(struct irq_data *d)
159{
160 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
161 io_be_clrbit(&intr->ctrl, 11 - l2irq);
162}
163
164static void mpc52xx_extirq_unmask(struct irq_data *d)
165{
166 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
167 io_be_setbit(&intr->ctrl, 11 - l2irq);
168}
169
170static void mpc52xx_extirq_ack(struct irq_data *d)
171{
172 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
173 io_be_setbit(&intr->ctrl, 27-l2irq);
174}
175
176static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type)
177{
178 u32 ctrl_reg, type;
179 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
180 void *handler = handle_level_irq;
181
182 pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__,
183 (int) irqd_to_hwirq(d), l2irq, flow_type);
184
185 switch (flow_type) {
186 case IRQF_TRIGGER_HIGH: type = 0; break;
187 case IRQF_TRIGGER_RISING: type = 1; handler = handle_edge_irq; break;
188 case IRQF_TRIGGER_FALLING: type = 2; handler = handle_edge_irq; break;
189 case IRQF_TRIGGER_LOW: type = 3; break;
190 default:
191 type = 0;
192 }
193
194 ctrl_reg = in_be32(&intr->ctrl);
195 ctrl_reg &= ~(0x3 << (22 - (l2irq * 2)));
196 ctrl_reg |= (type << (22 - (l2irq * 2)));
197 out_be32(&intr->ctrl, ctrl_reg);
198
199 irq_set_handler_locked(d, handler);
200
201 return 0;
202}
203
204static struct irq_chip mpc52xx_extirq_irqchip = {
205 .name = "MPC52xx External",
206 .irq_mask = mpc52xx_extirq_mask,
207 .irq_unmask = mpc52xx_extirq_unmask,
208 .irq_ack = mpc52xx_extirq_ack,
209 .irq_set_type = mpc52xx_extirq_set_type,
210};
211
212
213
214
215static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type)
216{
217 return 0;
218}
219
220static void mpc52xx_main_mask(struct irq_data *d)
221{
222 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
223 io_be_setbit(&intr->main_mask, 16 - l2irq);
224}
225
226static void mpc52xx_main_unmask(struct irq_data *d)
227{
228 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
229 io_be_clrbit(&intr->main_mask, 16 - l2irq);
230}
231
232static struct irq_chip mpc52xx_main_irqchip = {
233 .name = "MPC52xx Main",
234 .irq_mask = mpc52xx_main_mask,
235 .irq_mask_ack = mpc52xx_main_mask,
236 .irq_unmask = mpc52xx_main_unmask,
237 .irq_set_type = mpc52xx_null_set_type,
238};
239
240
241
242
243static void mpc52xx_periph_mask(struct irq_data *d)
244{
245 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
246 io_be_setbit(&intr->per_mask, 31 - l2irq);
247}
248
249static void mpc52xx_periph_unmask(struct irq_data *d)
250{
251 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
252 io_be_clrbit(&intr->per_mask, 31 - l2irq);
253}
254
255static struct irq_chip mpc52xx_periph_irqchip = {
256 .name = "MPC52xx Peripherals",
257 .irq_mask = mpc52xx_periph_mask,
258 .irq_mask_ack = mpc52xx_periph_mask,
259 .irq_unmask = mpc52xx_periph_unmask,
260 .irq_set_type = mpc52xx_null_set_type,
261};
262
263
264
265
266static void mpc52xx_sdma_mask(struct irq_data *d)
267{
268 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
269 io_be_setbit(&sdma->IntMask, l2irq);
270}
271
272static void mpc52xx_sdma_unmask(struct irq_data *d)
273{
274 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
275 io_be_clrbit(&sdma->IntMask, l2irq);
276}
277
278static void mpc52xx_sdma_ack(struct irq_data *d)
279{
280 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
281 out_be32(&sdma->IntPend, 1 << l2irq);
282}
283
284static struct irq_chip mpc52xx_sdma_irqchip = {
285 .name = "MPC52xx SDMA",
286 .irq_mask = mpc52xx_sdma_mask,
287 .irq_unmask = mpc52xx_sdma_unmask,
288 .irq_ack = mpc52xx_sdma_ack,
289 .irq_set_type = mpc52xx_null_set_type,
290};
291
292
293
294
295static int mpc52xx_is_extirq(int l1, int l2)
296{
297 return ((l1 == 0) && (l2 == 0)) ||
298 ((l1 == 1) && (l2 >= 1) && (l2 <= 3));
299}
300
301
302
303
304static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,
305 const u32 *intspec, unsigned int intsize,
306 irq_hw_number_t *out_hwirq,
307 unsigned int *out_flags)
308{
309 int intrvect_l1;
310 int intrvect_l2;
311 int intrvect_type;
312 int intrvect_linux;
313
314 if (intsize != 3)
315 return -1;
316
317 intrvect_l1 = (int)intspec[0];
318 intrvect_l2 = (int)intspec[1];
319 intrvect_type = (int)intspec[2] & 0x3;
320
321 intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) &
322 MPC52xx_IRQ_L1_MASK;
323 intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK;
324
325 *out_hwirq = intrvect_linux;
326 *out_flags = IRQ_TYPE_LEVEL_LOW;
327 if (mpc52xx_is_extirq(intrvect_l1, intrvect_l2))
328 *out_flags = mpc52xx_map_senses[intrvect_type];
329
330 pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
331 intrvect_l2);
332 return 0;
333}
334
335
336
337
338static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,
339 irq_hw_number_t irq)
340{
341 int l1irq;
342 int l2irq;
343 struct irq_chip *uninitialized_var(irqchip);
344 void *hndlr;
345 int type;
346 u32 reg;
347
348 l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
349 l2irq = irq & MPC52xx_IRQ_L2_MASK;
350
351
352
353
354
355 if (mpc52xx_is_extirq(l1irq, l2irq)) {
356 reg = in_be32(&intr->ctrl);
357 type = mpc52xx_map_senses[(reg >> (22 - l2irq * 2)) & 0x3];
358 if ((type == IRQ_TYPE_EDGE_FALLING) ||
359 (type == IRQ_TYPE_EDGE_RISING))
360 hndlr = handle_edge_irq;
361 else
362 hndlr = handle_level_irq;
363
364 irq_set_chip_and_handler(virq, &mpc52xx_extirq_irqchip, hndlr);
365 pr_debug("%s: External IRQ%i virq=%x, hw=%x. type=%x\n",
366 __func__, l2irq, virq, (int)irq, type);
367 return 0;
368 }
369
370
371 switch (l1irq) {
372 case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break;
373 case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break;
374 case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break;
375 case MPC52xx_IRQ_L1_CRIT:
376 pr_warn("%s: Critical IRQ #%d is unsupported! Nopping it.\n",
377 __func__, l2irq);
378 irq_set_chip(virq, &no_irq_chip);
379 return 0;
380 }
381
382 irq_set_chip_and_handler(virq, irqchip, handle_level_irq);
383 pr_debug("%s: virq=%x, l1=%i, l2=%i\n", __func__, virq, l1irq, l2irq);
384
385 return 0;
386}
387
388static const struct irq_domain_ops mpc52xx_irqhost_ops = {
389 .xlate = mpc52xx_irqhost_xlate,
390 .map = mpc52xx_irqhost_map,
391};
392
393
394
395
396
397
398
399
400
401
402void __init mpc52xx_init_irq(void)
403{
404 u32 intr_ctrl;
405 struct device_node *picnode;
406 struct device_node *np;
407
408
409 picnode = of_find_matching_node(NULL, mpc52xx_pic_ids);
410 intr = of_iomap(picnode, 0);
411 if (!intr)
412 panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. "
413 "Check node !");
414
415 np = of_find_matching_node(NULL, mpc52xx_sdma_ids);
416 sdma = of_iomap(np, 0);
417 of_node_put(np);
418 if (!sdma)
419 panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. "
420 "Check node !");
421
422 pr_debug("MPC5200 IRQ controller mapped to 0x%p\n", intr);
423
424
425 out_be32(&sdma->IntPend, 0xffffffff);
426 out_be32(&sdma->IntMask, 0xffffffff);
427 out_be32(&intr->per_mask, 0x7ffffc00);
428 out_be32(&intr->main_mask, 0x00010fff);
429 intr_ctrl = in_be32(&intr->ctrl);
430 intr_ctrl &= 0x00ff0000;
431 intr_ctrl |= 0x0f000000 |
432 0x00001000 |
433 0x00000000 |
434 0x00000001;
435 out_be32(&intr->ctrl, intr_ctrl);
436
437
438 out_be32(&intr->per_pri1, 0);
439 out_be32(&intr->per_pri2, 0);
440 out_be32(&intr->per_pri3, 0);
441 out_be32(&intr->main_pri1, 0);
442 out_be32(&intr->main_pri2, 0);
443
444
445
446
447
448 mpc52xx_irqhost = irq_domain_add_linear(picnode,
449 MPC52xx_IRQ_HIGHTESTHWIRQ,
450 &mpc52xx_irqhost_ops, NULL);
451
452 if (!mpc52xx_irqhost)
453 panic(__FILE__ ": Cannot allocate the IRQ host\n");
454
455 irq_set_default_host(mpc52xx_irqhost);
456
457 pr_info("MPC52xx PIC is up and running!\n");
458}
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487unsigned int mpc52xx_get_irq(void)
488{
489 u32 status;
490 int irq;
491
492 status = in_be32(&intr->enc_status);
493 if (status & 0x00000400) {
494 irq = (status >> 8) & 0x3;
495 if (irq == 2)
496 goto peripheral;
497 irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET);
498 } else if (status & 0x00200000) {
499 irq = (status >> 16) & 0x1f;
500 if (irq == 4)
501 goto peripheral;
502 irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET);
503 } else if (status & 0x20000000) {
504 peripheral:
505 irq = (status >> 24) & 0x1f;
506 if (irq == 0) {
507 status = in_be32(&sdma->IntPend);
508 irq = ffs(status) - 1;
509 irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET);
510 } else {
511 irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
512 }
513 } else {
514 return 0;
515 }
516
517 return irq_linear_revmap(mpc52xx_irqhost, irq);
518}
519