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 42 static struct mpc52xx_intr __iomem *intr; 43 static struct mpc52xx_sdma __iomem *sdma; 44 static struct irq_host *mpc52xx_irqhost = NULL; 45 46 static 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 57 static inline void io_be_setbit(u32 __iomem *addr, int bitno) 58 { 59 out_be32(addr, in_be32(addr) | (1 << bitno)); 60 } 61 62 static 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 71 static 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 84 static 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 97 static 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 110 static 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 121 static 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, 16 - l2irq); 132 } 133 134 static 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, 16 - l2irq); 145 } 146 147 static 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 158 static 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 171 static 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 184 static 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 195 static 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 208 static 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 221 static 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 234 static 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 245 static 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 251 static 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 */ 287 static 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 298 static 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 370 static 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 380 void __init mpc52xx_init_irq(void) 381 { 382 u32 intr_ctrl; 383 struct device_node *picnode; 384 385 /* Remap the necessary zones */ 386 picnode = of_find_compatible_node(NULL, NULL, "mpc5200-pic"); 387 388 intr = mpc52xx_find_and_map("mpc5200-pic"); 389 if (!intr) 390 panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. " 391 "Check node !"); 392 393 sdma = mpc52xx_find_and_map("mpc5200-bestcomm"); 394 if (!sdma) 395 panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " 396 "Check node !"); 397 398 /* Disable all interrupt sources. */ 399 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */ 400 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */ 401 out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */ 402 out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */ 403 intr_ctrl = in_be32(&intr->ctrl); 404 intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */ 405 intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */ 406 0x00001000 | /* MEE master external enable */ 407 0x00000000 | /* 0 means disable IRQ 0-3 */ 408 0x00000001; /* CEb route critical normally */ 409 out_be32(&intr->ctrl, intr_ctrl); 410 411 /* Zero a bunch of the priority settings. */ 412 out_be32(&intr->per_pri1, 0); 413 out_be32(&intr->per_pri2, 0); 414 out_be32(&intr->per_pri3, 0); 415 out_be32(&intr->main_pri1, 0); 416 out_be32(&intr->main_pri2, 0); 417 418 /* 419 * As last step, add an irq host to translate the real 420 * hw irq information provided by the ofw to linux virq 421 */ 422 423 mpc52xx_irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 424 MPC52xx_IRQ_HIGHTESTHWIRQ, 425 &mpc52xx_irqhost_ops, -1); 426 427 if (!mpc52xx_irqhost) 428 panic(__FILE__ ": Cannot allocate the IRQ host\n"); 429 430 mpc52xx_irqhost->host_data = picnode; 431 printk(KERN_INFO "MPC52xx PIC is up and running!\n"); 432 } 433 434 /* 435 * get_irq (public) 436 */ 437 unsigned int mpc52xx_get_irq(void) 438 { 439 u32 status; 440 int irq = NO_IRQ_IGNORE; 441 442 status = in_be32(&intr->enc_status); 443 if (status & 0x00000400) { /* critical */ 444 irq = (status >> 8) & 0x3; 445 if (irq == 2) /* high priority peripheral */ 446 goto peripheral; 447 irq |= (MPC52xx_IRQ_L1_CRIT << MPC52xx_IRQ_L1_OFFSET) & 448 MPC52xx_IRQ_L1_MASK; 449 } else if (status & 0x00200000) { /* main */ 450 irq = (status >> 16) & 0x1f; 451 if (irq == 4) /* low priority peripheral */ 452 goto peripheral; 453 irq |= (MPC52xx_IRQ_L1_MAIN << MPC52xx_IRQ_L1_OFFSET) & 454 MPC52xx_IRQ_L1_MASK; 455 } else if (status & 0x20000000) { /* peripheral */ 456 peripheral: 457 irq = (status >> 24) & 0x1f; 458 if (irq == 0) { /* bestcomm */ 459 status = in_be32(&sdma->IntPend); 460 irq = ffs(status) - 1; 461 irq |= (MPC52xx_IRQ_L1_SDMA << MPC52xx_IRQ_L1_OFFSET) & 462 MPC52xx_IRQ_L1_MASK; 463 } else { 464 irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET) & 465 MPC52xx_IRQ_L1_MASK; 466 } 467 } 468 469 pr_debug("%s: irq=%x. virq=%d\n", __func__, irq, 470 irq_linear_revmap(mpc52xx_irqhost, irq)); 471 472 return irq_linear_revmap(mpc52xx_irqhost, irq); 473 } 474