1 /* 2 * 3 * Programmable Interrupt Controller functions for the Freescale MPC52xx. 4 * 5 * Copyright (C) 2006 bplan GmbH 6 * 7 * Based on the code from the 2.4 kernel by 8 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg. 9 * 10 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> 11 * Copyright (C) 2003 Montavista Software, Inc 12 * 13 * This file is licensed under the terms of the GNU General Public License 14 * version 2. This program is licensed "as is" without any warranty of any 15 * kind, whether express or implied. 16 * 17 */ 18 19 #undef DEBUG 20 21 #include <linux/interrupt.h> 22 #include <linux/irq.h> 23 #include <linux/of.h> 24 #include <asm/io.h> 25 #include <asm/prom.h> 26 #include <asm/mpc52xx.h> 27 #include "mpc52xx_pic.h" 28 29 /* 30 * 31 */ 32 33 /* MPC5200 device tree match tables */ 34 static struct of_device_id mpc52xx_pic_ids[] __initdata = { 35 { .compatible = "fsl,mpc5200-pic", }, 36 { .compatible = "mpc5200-pic", }, 37 {} 38 }; 39 static struct of_device_id mpc52xx_sdma_ids[] __initdata = { 40 { .compatible = "fsl,mpc5200-bestcomm", }, 41 { .compatible = "mpc5200-bestcomm", }, 42 {} 43 }; 44 45 static struct mpc52xx_intr __iomem *intr; 46 static struct mpc52xx_sdma __iomem *sdma; 47 static struct irq_host *mpc52xx_irqhost = NULL; 48 49 static unsigned char mpc52xx_map_senses[4] = { 50 IRQ_TYPE_LEVEL_HIGH, 51 IRQ_TYPE_EDGE_RISING, 52 IRQ_TYPE_EDGE_FALLING, 53 IRQ_TYPE_LEVEL_LOW, 54 }; 55 56 /* 57 * 58 */ 59 60 static inline void io_be_setbit(u32 __iomem *addr, int bitno) 61 { 62 out_be32(addr, in_be32(addr) | (1 << bitno)); 63 } 64 65 static inline void io_be_clrbit(u32 __iomem *addr, int bitno) 66 { 67 out_be32(addr, in_be32(addr) & ~(1 << bitno)); 68 } 69 70 /* 71 * IRQ[0-3] interrupt irq_chip 72 */ 73 74 static void mpc52xx_extirq_mask(unsigned int virq) 75 { 76 int irq; 77 int l2irq; 78 79 irq = irq_map[virq].hwirq; 80 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 81 82 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 83 84 io_be_clrbit(&intr->ctrl, 11 - l2irq); 85 } 86 87 static void mpc52xx_extirq_unmask(unsigned int virq) 88 { 89 int irq; 90 int l2irq; 91 92 irq = irq_map[virq].hwirq; 93 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 94 95 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 96 97 io_be_setbit(&intr->ctrl, 11 - l2irq); 98 } 99 100 static void mpc52xx_extirq_ack(unsigned int virq) 101 { 102 int irq; 103 int l2irq; 104 105 irq = irq_map[virq].hwirq; 106 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 107 108 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 109 110 io_be_setbit(&intr->ctrl, 27-l2irq); 111 } 112 113 static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) 114 { 115 u32 ctrl_reg, type; 116 int irq; 117 int l2irq; 118 119 irq = irq_map[virq].hwirq; 120 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 121 122 pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type); 123 124 switch (flow_type) { 125 case IRQF_TRIGGER_HIGH: 126 type = 0; 127 break; 128 case IRQF_TRIGGER_RISING: 129 type = 1; 130 break; 131 case IRQF_TRIGGER_FALLING: 132 type = 2; 133 break; 134 case IRQF_TRIGGER_LOW: 135 type = 3; 136 break; 137 default: 138 type = 0; 139 } 140 141 ctrl_reg = in_be32(&intr->ctrl); 142 ctrl_reg &= ~(0x3 << (22 - (l2irq * 2))); 143 ctrl_reg |= (type << (22 - (l2irq * 2))); 144 out_be32(&intr->ctrl, ctrl_reg); 145 146 return 0; 147 } 148 149 static struct irq_chip mpc52xx_extirq_irqchip = { 150 .typename = " MPC52xx IRQ[0-3] ", 151 .mask = mpc52xx_extirq_mask, 152 .unmask = mpc52xx_extirq_unmask, 153 .ack = mpc52xx_extirq_ack, 154 .set_type = mpc52xx_extirq_set_type, 155 }; 156 157 /* 158 * Main interrupt irq_chip 159 */ 160 161 static void mpc52xx_main_mask(unsigned int virq) 162 { 163 int irq; 164 int l2irq; 165 166 irq = irq_map[virq].hwirq; 167 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 168 169 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 170 171 io_be_setbit(&intr->main_mask, 16 - l2irq); 172 } 173 174 static void mpc52xx_main_unmask(unsigned int virq) 175 { 176 int irq; 177 int l2irq; 178 179 irq = irq_map[virq].hwirq; 180 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 181 182 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 183 184 io_be_clrbit(&intr->main_mask, 16 - l2irq); 185 } 186 187 static struct irq_chip mpc52xx_main_irqchip = { 188 .typename = "MPC52xx Main", 189 .mask = mpc52xx_main_mask, 190 .mask_ack = mpc52xx_main_mask, 191 .unmask = mpc52xx_main_unmask, 192 }; 193 194 /* 195 * Peripherals interrupt irq_chip 196 */ 197 198 static void mpc52xx_periph_mask(unsigned int virq) 199 { 200 int irq; 201 int l2irq; 202 203 irq = irq_map[virq].hwirq; 204 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 205 206 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 207 208 io_be_setbit(&intr->per_mask, 31 - l2irq); 209 } 210 211 static void mpc52xx_periph_unmask(unsigned int virq) 212 { 213 int irq; 214 int l2irq; 215 216 irq = irq_map[virq].hwirq; 217 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 218 219 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 220 221 io_be_clrbit(&intr->per_mask, 31 - l2irq); 222 } 223 224 static struct irq_chip mpc52xx_periph_irqchip = { 225 .typename = "MPC52xx Peripherals", 226 .mask = mpc52xx_periph_mask, 227 .mask_ack = mpc52xx_periph_mask, 228 .unmask = mpc52xx_periph_unmask, 229 }; 230 231 /* 232 * SDMA interrupt irq_chip 233 */ 234 235 static void mpc52xx_sdma_mask(unsigned int virq) 236 { 237 int irq; 238 int l2irq; 239 240 irq = irq_map[virq].hwirq; 241 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 242 243 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 244 245 io_be_setbit(&sdma->IntMask, l2irq); 246 } 247 248 static void mpc52xx_sdma_unmask(unsigned int virq) 249 { 250 int irq; 251 int l2irq; 252 253 irq = irq_map[virq].hwirq; 254 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 255 256 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 257 258 io_be_clrbit(&sdma->IntMask, l2irq); 259 } 260 261 static void mpc52xx_sdma_ack(unsigned int virq) 262 { 263 int irq; 264 int l2irq; 265 266 irq = irq_map[virq].hwirq; 267 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 268 269 pr_debug("%s: irq=%x. l2=%d\n", __func__, irq, l2irq); 270 271 out_be32(&sdma->IntPend, 1 << l2irq); 272 } 273 274 static struct irq_chip mpc52xx_sdma_irqchip = { 275 .typename = "MPC52xx SDMA", 276 .mask = mpc52xx_sdma_mask, 277 .unmask = mpc52xx_sdma_unmask, 278 .ack = mpc52xx_sdma_ack, 279 }; 280 281 /* 282 * irq_host 283 */ 284 285 static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, 286 u32 * intspec, unsigned int intsize, 287 irq_hw_number_t * out_hwirq, 288 unsigned int *out_flags) 289 { 290 int intrvect_l1; 291 int intrvect_l2; 292 int intrvect_type; 293 int intrvect_linux; 294 295 if (intsize != 3) 296 return -1; 297 298 intrvect_l1 = (int)intspec[0]; 299 intrvect_l2 = (int)intspec[1]; 300 intrvect_type = (int)intspec[2]; 301 302 intrvect_linux = 303 (intrvect_l1 << MPC52xx_IRQ_L1_OFFSET) & MPC52xx_IRQ_L1_MASK; 304 intrvect_linux |= 305 (intrvect_l2 << MPC52xx_IRQ_L2_OFFSET) & MPC52xx_IRQ_L2_MASK; 306 307 pr_debug("return %x, l1=%d, l2=%d\n", intrvect_linux, intrvect_l1, 308 intrvect_l2); 309 310 *out_hwirq = intrvect_linux; 311 *out_flags = mpc52xx_map_senses[intrvect_type]; 312 313 return 0; 314 } 315 316 /* 317 * this function retrieves the correct IRQ type out 318 * of the MPC regs 319 * Only externals IRQs needs this 320 */ 321 static int mpc52xx_irqx_gettype(int irq) 322 { 323 int type; 324 u32 ctrl_reg; 325 326 ctrl_reg = in_be32(&intr->ctrl); 327 type = (ctrl_reg >> (22 - irq * 2)) & 0x3; 328 329 return mpc52xx_map_senses[type]; 330 } 331 332 static int mpc52xx_irqhost_map(struct irq_host *h, unsigned int virq, 333 irq_hw_number_t irq) 334 { 335 int l1irq; 336 int l2irq; 337 struct irq_chip *good_irqchip; 338 void *good_handle; 339 int type; 340 341 l1irq = (irq & MPC52xx_IRQ_L1_MASK) >> MPC52xx_IRQ_L1_OFFSET; 342 l2irq = (irq & MPC52xx_IRQ_L2_MASK) >> MPC52xx_IRQ_L2_OFFSET; 343 344 /* 345 * Most of ours IRQs will be level low 346 * Only external IRQs on some platform may be others 347 */ 348 type = IRQ_TYPE_LEVEL_LOW; 349 350 switch (l1irq) { 351 case MPC52xx_IRQ_L1_CRIT: 352 pr_debug("%s: Critical. l2=%x\n", __func__, l2irq); 353 354 BUG_ON(l2irq != 0); 355 356 type = mpc52xx_irqx_gettype(l2irq); 357 good_irqchip = &mpc52xx_extirq_irqchip; 358 break; 359 360 case MPC52xx_IRQ_L1_MAIN: 361 pr_debug("%s: Main IRQ[1-3] l2=%x\n", __func__, l2irq); 362 363 if ((l2irq >= 1) && (l2irq <= 3)) { 364 type = mpc52xx_irqx_gettype(l2irq); 365 good_irqchip = &mpc52xx_extirq_irqchip; 366 } else { 367 good_irqchip = &mpc52xx_main_irqchip; 368 } 369 break; 370 371 case MPC52xx_IRQ_L1_PERP: 372 pr_debug("%s: Peripherals. l2=%x\n", __func__, l2irq); 373 good_irqchip = &mpc52xx_periph_irqchip; 374 break; 375 376 case MPC52xx_IRQ_L1_SDMA: 377 pr_debug("%s: SDMA. l2=%x\n", __func__, l2irq); 378 good_irqchip = &mpc52xx_sdma_irqchip; 379 break; 380 381 default: 382 pr_debug("%s: Error, unknown L1 IRQ (0x%x)\n", __func__, l1irq); 383 printk(KERN_ERR "Unknow IRQ!\n"); 384 return -EINVAL; 385 } 386 387 switch (type) { 388 case IRQ_TYPE_EDGE_FALLING: 389 case IRQ_TYPE_EDGE_RISING: 390 good_handle = handle_edge_irq; 391 break; 392 default: 393 good_handle = handle_level_irq; 394 } 395 396 set_irq_chip_and_handler(virq, good_irqchip, good_handle); 397 398 pr_debug("%s: virq=%x, hw=%x. type=%x\n", __func__, virq, 399 (int)irq, type); 400 401 return 0; 402 } 403 404 static struct irq_host_ops mpc52xx_irqhost_ops = { 405 .xlate = mpc52xx_irqhost_xlate, 406 .map = mpc52xx_irqhost_map, 407 }; 408 409 /* 410 * init (public) 411 */ 412 413 void __init mpc52xx_init_irq(void) 414 { 415 u32 intr_ctrl; 416 struct device_node *picnode; 417 struct device_node *np; 418 419 /* Remap the necessary zones */ 420 picnode = of_find_matching_node(NULL, mpc52xx_pic_ids); 421 intr = of_iomap(picnode, 0); 422 if (!intr) 423 panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. " 424 "Check node !"); 425 426 np = of_find_matching_node(NULL, mpc52xx_sdma_ids); 427 sdma = of_iomap(np, 0); 428 of_node_put(np); 429 if (!sdma) 430 panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " 431 "Check node !"); 432 433 /* Disable all interrupt sources. */ 434 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ 435 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ 436 out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ 437 out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ 438 intr_ctrl = in_be32(&intr->ctrl); 439 intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ 440 intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ 441 0x00001000 | /* MEE master external enable */ 442 0x00000000 | /* 0 means disable IRQ 0-3 */ 443 0x00000001; /* CEb route critical normally */ 444 out_be32(&intr->ctrl, intr_ctrl); 445 446 /* Zero a bunch of the priority settings. */ 447 out_be32(&intr->per_pri1, 0); 448 out_be32(&intr->per_pri2, 0); 449 out_be32(&intr->per_pri3, 0); 450 out_be32(&intr->main_pri1, 0); 451 out_be32(&intr->main_pri2, 0); 452 453 /* 454 * As last step, add an irq host to translate the real 455 * hw irq information provided by the ofw to linux virq 456 */ 457 458 mpc52xx_irqhost = irq_alloc_host(picnode, IRQ_HOST_MAP_LINEAR, 459 MPC52xx_IRQ_HIGHTESTHWIRQ, 460 &mpc52xx_irqhost_ops, -1); 461 462 if (!mpc52xx_irqhost) 463 panic(__FILE__ ": Cannot allocate the IRQ host\n"); 464 465 printk(KERN_INFO "MPC52xx PIC is up and running!\n"); 466 } 467 468 /* 469 * get_irq (public) 470 */ 471 unsigned int mpc52xx_get_irq(void) 472 { 473 u32 status; 474 int irq = NO_IRQ_IGNORE; 475 476 status = in_be32(&intr->enc_status); 477 if (status & 0x00000400) { /* critical */ 478 irq = (status >> 8) & 0x3; 479 if (irq == 2) /* high priority peripheral */ 480 goto peripheral; 481 irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & 482 MPC52xx_IRQ_L1_MASK; 483 } else if (status & 0x00200000) { /* main */ 484 irq = (status >> 16) & 0x1f; 485 if (irq == 4) /* low priority peripheral */ 486 goto peripheral; 487 irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & 488 MPC52xx_IRQ_L1_MASK; 489 } else if (status & 0x20000000) { /* peripheral */ 490 peripheral: 491 irq = (status >> 24) & 0x1f; 492 if (irq == 0) { /* bestcomm */ 493 status = in_be32(&sdma->IntPend); 494 irq = ffs(status) - 1; 495 irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & 496 MPC52xx_IRQ_L1_MASK; 497 } else { 498 irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & 499 MPC52xx_IRQ_L1_MASK; 500 } 501 } 502 503 pr_debug("%s: irq=%x. virq=%d\n", __func__, irq, 504 irq_linear_revmap(mpc52xx_irqhost, irq)); 505 506 return irq_linear_revmap(mpc52xx_irqhost, irq); 507 } 508