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