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