0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 #undef DEBUG
0100
0101 #include <linux/interrupt.h>
0102 #include <linux/irq.h>
0103 #include <linux/of.h>
0104 #include <linux/of_address.h>
0105 #include <linux/of_irq.h>
0106 #include <asm/io.h>
0107 #include <asm/mpc52xx.h>
0108
0109
0110 #define MPC52xx_IRQ_L1_CRIT (0)
0111 #define MPC52xx_IRQ_L1_MAIN (1)
0112 #define MPC52xx_IRQ_L1_PERP (2)
0113 #define MPC52xx_IRQ_L1_SDMA (3)
0114
0115 #define MPC52xx_IRQ_L1_OFFSET (6)
0116 #define MPC52xx_IRQ_L1_MASK (0x00c0)
0117 #define MPC52xx_IRQ_L2_MASK (0x003f)
0118
0119 #define MPC52xx_IRQ_HIGHTESTHWIRQ (0xd0)
0120
0121
0122
0123 static const struct of_device_id mpc52xx_pic_ids[] __initconst = {
0124 { .compatible = "fsl,mpc5200-pic", },
0125 { .compatible = "mpc5200-pic", },
0126 {}
0127 };
0128 static const struct of_device_id mpc52xx_sdma_ids[] __initconst = {
0129 { .compatible = "fsl,mpc5200-bestcomm", },
0130 { .compatible = "mpc5200-bestcomm", },
0131 {}
0132 };
0133
0134 static struct mpc52xx_intr __iomem *intr;
0135 static struct mpc52xx_sdma __iomem *sdma;
0136 static struct irq_domain *mpc52xx_irqhost = NULL;
0137
0138 static unsigned char mpc52xx_map_senses[4] = {
0139 IRQ_TYPE_LEVEL_HIGH,
0140 IRQ_TYPE_EDGE_RISING,
0141 IRQ_TYPE_EDGE_FALLING,
0142 IRQ_TYPE_LEVEL_LOW,
0143 };
0144
0145
0146 static inline void io_be_setbit(u32 __iomem *addr, int bitno)
0147 {
0148 out_be32(addr, in_be32(addr) | (1 << bitno));
0149 }
0150
0151 static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
0152 {
0153 out_be32(addr, in_be32(addr) & ~(1 << bitno));
0154 }
0155
0156
0157
0158
0159 static void mpc52xx_extirq_mask(struct irq_data *d)
0160 {
0161 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0162 io_be_clrbit(&intr->ctrl, 11 - l2irq);
0163 }
0164
0165 static void mpc52xx_extirq_unmask(struct irq_data *d)
0166 {
0167 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0168 io_be_setbit(&intr->ctrl, 11 - l2irq);
0169 }
0170
0171 static void mpc52xx_extirq_ack(struct irq_data *d)
0172 {
0173 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0174 io_be_setbit(&intr->ctrl, 27-l2irq);
0175 }
0176
0177 static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type)
0178 {
0179 u32 ctrl_reg, type;
0180 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0181 void *handler = handle_level_irq;
0182
0183 pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__,
0184 (int) irqd_to_hwirq(d), l2irq, flow_type);
0185
0186 switch (flow_type) {
0187 case IRQF_TRIGGER_HIGH: type = 0; break;
0188 case IRQF_TRIGGER_RISING: type = 1; handler = handle_edge_irq; break;
0189 case IRQF_TRIGGER_FALLING: type = 2; handler = handle_edge_irq; break;
0190 case IRQF_TRIGGER_LOW: type = 3; break;
0191 default:
0192 type = 0;
0193 }
0194
0195 ctrl_reg = in_be32(&intr->ctrl);
0196 ctrl_reg &= ~(0x3 << (22 - (l2irq * 2)));
0197 ctrl_reg |= (type << (22 - (l2irq * 2)));
0198 out_be32(&intr->ctrl, ctrl_reg);
0199
0200 irq_set_handler_locked(d, handler);
0201
0202 return 0;
0203 }
0204
0205 static struct irq_chip mpc52xx_extirq_irqchip = {
0206 .name = "MPC52xx External",
0207 .irq_mask = mpc52xx_extirq_mask,
0208 .irq_unmask = mpc52xx_extirq_unmask,
0209 .irq_ack = mpc52xx_extirq_ack,
0210 .irq_set_type = mpc52xx_extirq_set_type,
0211 };
0212
0213
0214
0215
0216 static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type)
0217 {
0218 return 0;
0219 }
0220
0221 static void mpc52xx_main_mask(struct irq_data *d)
0222 {
0223 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0224 io_be_setbit(&intr->main_mask, 16 - l2irq);
0225 }
0226
0227 static void mpc52xx_main_unmask(struct irq_data *d)
0228 {
0229 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0230 io_be_clrbit(&intr->main_mask, 16 - l2irq);
0231 }
0232
0233 static struct irq_chip mpc52xx_main_irqchip = {
0234 .name = "MPC52xx Main",
0235 .irq_mask = mpc52xx_main_mask,
0236 .irq_mask_ack = mpc52xx_main_mask,
0237 .irq_unmask = mpc52xx_main_unmask,
0238 .irq_set_type = mpc52xx_null_set_type,
0239 };
0240
0241
0242
0243
0244 static void mpc52xx_periph_mask(struct irq_data *d)
0245 {
0246 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0247 io_be_setbit(&intr->per_mask, 31 - l2irq);
0248 }
0249
0250 static void mpc52xx_periph_unmask(struct irq_data *d)
0251 {
0252 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0253 io_be_clrbit(&intr->per_mask, 31 - l2irq);
0254 }
0255
0256 static struct irq_chip mpc52xx_periph_irqchip = {
0257 .name = "MPC52xx Peripherals",
0258 .irq_mask = mpc52xx_periph_mask,
0259 .irq_mask_ack = mpc52xx_periph_mask,
0260 .irq_unmask = mpc52xx_periph_unmask,
0261 .irq_set_type = mpc52xx_null_set_type,
0262 };
0263
0264
0265
0266
0267 static void mpc52xx_sdma_mask(struct irq_data *d)
0268 {
0269 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0270 io_be_setbit(&sdma->IntMask, l2irq);
0271 }
0272
0273 static void mpc52xx_sdma_unmask(struct irq_data *d)
0274 {
0275 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0276 io_be_clrbit(&sdma->IntMask, l2irq);
0277 }
0278
0279 static void mpc52xx_sdma_ack(struct irq_data *d)
0280 {
0281 int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
0282 out_be32(&sdma->IntPend, 1 << l2irq);
0283 }
0284
0285 static struct irq_chip mpc52xx_sdma_irqchip = {
0286 .name = "MPC52xx SDMA",
0287 .irq_mask = mpc52xx_sdma_mask,
0288 .irq_unmask = mpc52xx_sdma_unmask,
0289 .irq_ack = mpc52xx_sdma_ack,
0290 .irq_set_type = mpc52xx_null_set_type,
0291 };
0292
0293
0294
0295
0296 static int mpc52xx_is_extirq(int l1, int l2)
0297 {
0298 return ((l1 == 0) && (l2 == 0)) ||
0299 ((l1 == 1) && (l2 >= 1) && (l2 <= 3));
0300 }
0301
0302
0303
0304
0305 static int mpc52xx_irqhost_xlate(struct irq_domain *h, struct device_node *ct,
0306 const u32 *intspec, unsigned int intsize,
0307 irq_hw_number_t *out_hwirq,
0308 unsigned int *out_flags)
0309 {
0310 int intrvect_l1;
0311 int intrvect_l2;
0312 int intrvect_type;
0313 int intrvect_linux;
0314
0315 if (intsize != 3)
0316 return -1;
0317
0318 intrvect_l1 = (int)intspec[0];
0319 intrvect_l2 = (int)intspec[1];
0320 intrvect_type = (int)intspec[2] & 0x3;
0321
0322 intrvect_linux = (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) &
0323 MPC52xx_IRQ_L1_MASK;
0324 intrvect_linux |= intrvect_l2 & MPC52xx_IRQ_L2_MASK;
0325
0326 *out_hwirq = intrvect_linux;
0327 *out_flags = IRQ_TYPE_LEVEL_LOW;
0328 if (mpc52xx_is_extirq(intrvect_l1, intrvect_l2))
0329 *out_flags = mpc52xx_map_senses[intrvect_type];
0330
0331 pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1,
0332 intrvect_l2);
0333 return 0;
0334 }
0335
0336
0337
0338
0339 static int mpc52xx_irqhost_map(struct irq_domain *h, unsigned int virq,
0340 irq_hw_number_t irq)
0341 {
0342 int l1irq;
0343 int l2irq;
0344 struct irq_chip *irqchip;
0345 void *hndlr;
0346 int type;
0347 u32 reg;
0348
0349 l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET;
0350 l2irq = irq & MPC52xx_IRQ_L2_MASK;
0351
0352
0353
0354
0355
0356 if (mpc52xx_is_extirq(l1irq, l2irq)) {
0357 reg = in_be32(&intr->ctrl);
0358 type = mpc52xx_map_senses[(reg >> (22 - l2irq * 2)) & 0x3];
0359 if ((type == IRQ_TYPE_EDGE_FALLING) ||
0360 (type == IRQ_TYPE_EDGE_RISING))
0361 hndlr = handle_edge_irq;
0362 else
0363 hndlr = handle_level_irq;
0364
0365 irq_set_chip_and_handler(virq, &mpc52xx_extirq_irqchip, hndlr);
0366 pr_debug("%s: External IRQ%i virq=%x, hw=%x. type=%x\n",
0367 __func__, l2irq, virq, (int)irq, type);
0368 return 0;
0369 }
0370
0371
0372 switch (l1irq) {
0373 case MPC52xx_IRQ_L1_MAIN: irqchip = &mpc52xx_main_irqchip; break;
0374 case MPC52xx_IRQ_L1_PERP: irqchip = &mpc52xx_periph_irqchip; break;
0375 case MPC52xx_IRQ_L1_SDMA: irqchip = &mpc52xx_sdma_irqchip; break;
0376 case MPC52xx_IRQ_L1_CRIT:
0377 pr_warn("%s: Critical IRQ #%d is unsupported! Nopping it.\n",
0378 __func__, l2irq);
0379 irq_set_chip(virq, &no_irq_chip);
0380 return 0;
0381 }
0382
0383 irq_set_chip_and_handler(virq, irqchip, handle_level_irq);
0384 pr_debug("%s: virq=%x, l1=%i, l2=%i\n", __func__, virq, l1irq, l2irq);
0385
0386 return 0;
0387 }
0388
0389 static const struct irq_domain_ops mpc52xx_irqhost_ops = {
0390 .xlate = mpc52xx_irqhost_xlate,
0391 .map = mpc52xx_irqhost_map,
0392 };
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403 void __init mpc52xx_init_irq(void)
0404 {
0405 u32 intr_ctrl;
0406 struct device_node *picnode;
0407 struct device_node *np;
0408
0409
0410 picnode = of_find_matching_node(NULL, mpc52xx_pic_ids);
0411 intr = of_iomap(picnode, 0);
0412 if (!intr)
0413 panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. "
0414 "Check node !");
0415
0416 np = of_find_matching_node(NULL, mpc52xx_sdma_ids);
0417 sdma = of_iomap(np, 0);
0418 of_node_put(np);
0419 if (!sdma)
0420 panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. "
0421 "Check node !");
0422
0423 pr_debug("MPC5200 IRQ controller mapped to 0x%p\n", intr);
0424
0425
0426 out_be32(&sdma->IntPend, 0xffffffff);
0427 out_be32(&sdma->IntMask, 0xffffffff);
0428 out_be32(&intr->per_mask, 0x7ffffc00);
0429 out_be32(&intr->main_mask, 0x00010fff);
0430 intr_ctrl = in_be32(&intr->ctrl);
0431 intr_ctrl &= 0x00ff0000;
0432 intr_ctrl |= 0x0f000000 |
0433 0x00001000 |
0434 0x00000000 |
0435 0x00000001;
0436 out_be32(&intr->ctrl, intr_ctrl);
0437
0438
0439 out_be32(&intr->per_pri1, 0);
0440 out_be32(&intr->per_pri2, 0);
0441 out_be32(&intr->per_pri3, 0);
0442 out_be32(&intr->main_pri1, 0);
0443 out_be32(&intr->main_pri2, 0);
0444
0445
0446
0447
0448
0449 mpc52xx_irqhost = irq_domain_add_linear(picnode,
0450 MPC52xx_IRQ_HIGHTESTHWIRQ,
0451 &mpc52xx_irqhost_ops, NULL);
0452
0453 if (!mpc52xx_irqhost)
0454 panic(__FILE__ ": Cannot allocate the IRQ host\n");
0455
0456 irq_set_default_host(mpc52xx_irqhost);
0457
0458 pr_info("MPC52xx PIC is up and running!\n");
0459 }
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488 unsigned int mpc52xx_get_irq(void)
0489 {
0490 u32 status;
0491 int irq;
0492
0493 status = in_be32(&intr->enc_status);
0494 if (status & 0x00000400) {
0495 irq = (status >> 8) & 0x3;
0496 if (irq == 2)
0497 goto peripheral;
0498 irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET);
0499 } else if (status & 0x00200000) {
0500 irq = (status >> 16) & 0x1f;
0501 if (irq == 4)
0502 goto peripheral;
0503 irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET);
0504 } else if (status & 0x20000000) {
0505 peripheral:
0506 irq = (status >> 24) & 0x1f;
0507 if (irq == 0) {
0508 status = in_be32(&sdma->IntPend);
0509 irq = ffs(status) - 1;
0510 irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET);
0511 } else {
0512 irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
0513 }
0514 } else {
0515 return 0;
0516 }
0517
0518 return irq_linear_revmap(mpc52xx_irqhost, irq);
0519 }