1 /* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7 * Copyright (C) 2008 Nicolas Schichan <nschichan@freebox.fr> 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/init.h> 12 #include <linux/interrupt.h> 13 #include <linux/module.h> 14 #include <linux/irq.h> 15 #include <asm/irq_cpu.h> 16 #include <asm/mipsregs.h> 17 #include <bcm63xx_cpu.h> 18 #include <bcm63xx_regs.h> 19 #include <bcm63xx_io.h> 20 #include <bcm63xx_irq.h> 21 22 static void __dispatch_internal(void) __maybe_unused; 23 static void __dispatch_internal_64(void) __maybe_unused; 24 static void __internal_irq_mask_32(unsigned int irq) __maybe_unused; 25 static void __internal_irq_mask_64(unsigned int irq) __maybe_unused; 26 static void __internal_irq_unmask_32(unsigned int irq) __maybe_unused; 27 static void __internal_irq_unmask_64(unsigned int irq) __maybe_unused; 28 29 #ifndef BCMCPU_RUNTIME_DETECT 30 #ifdef CONFIG_BCM63XX_CPU_3368 31 #define irq_stat_reg PERF_IRQSTAT_3368_REG 32 #define irq_mask_reg PERF_IRQMASK_3368_REG 33 #define irq_bits 32 34 #define is_ext_irq_cascaded 0 35 #define ext_irq_start 0 36 #define ext_irq_end 0 37 #define ext_irq_count 4 38 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_3368 39 #define ext_irq_cfg_reg2 0 40 #endif 41 #ifdef CONFIG_BCM63XX_CPU_6328 42 #define irq_stat_reg PERF_IRQSTAT_6328_REG 43 #define irq_mask_reg PERF_IRQMASK_6328_REG 44 #define irq_bits 64 45 #define is_ext_irq_cascaded 1 46 #define ext_irq_start (BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE) 47 #define ext_irq_end (BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE) 48 #define ext_irq_count 4 49 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6328 50 #define ext_irq_cfg_reg2 0 51 #endif 52 #ifdef CONFIG_BCM63XX_CPU_6338 53 #define irq_stat_reg PERF_IRQSTAT_6338_REG 54 #define irq_mask_reg PERF_IRQMASK_6338_REG 55 #define irq_bits 32 56 #define is_ext_irq_cascaded 0 57 #define ext_irq_start 0 58 #define ext_irq_end 0 59 #define ext_irq_count 4 60 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6338 61 #define ext_irq_cfg_reg2 0 62 #endif 63 #ifdef CONFIG_BCM63XX_CPU_6345 64 #define irq_stat_reg PERF_IRQSTAT_6345_REG 65 #define irq_mask_reg PERF_IRQMASK_6345_REG 66 #define irq_bits 32 67 #define is_ext_irq_cascaded 0 68 #define ext_irq_start 0 69 #define ext_irq_end 0 70 #define ext_irq_count 4 71 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6345 72 #define ext_irq_cfg_reg2 0 73 #endif 74 #ifdef CONFIG_BCM63XX_CPU_6348 75 #define irq_stat_reg PERF_IRQSTAT_6348_REG 76 #define irq_mask_reg PERF_IRQMASK_6348_REG 77 #define irq_bits 32 78 #define is_ext_irq_cascaded 0 79 #define ext_irq_start 0 80 #define ext_irq_end 0 81 #define ext_irq_count 4 82 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6348 83 #define ext_irq_cfg_reg2 0 84 #endif 85 #ifdef CONFIG_BCM63XX_CPU_6358 86 #define irq_stat_reg PERF_IRQSTAT_6358_REG 87 #define irq_mask_reg PERF_IRQMASK_6358_REG 88 #define irq_bits 32 89 #define is_ext_irq_cascaded 1 90 #define ext_irq_start (BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE) 91 #define ext_irq_end (BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE) 92 #define ext_irq_count 4 93 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6358 94 #define ext_irq_cfg_reg2 0 95 #endif 96 #ifdef CONFIG_BCM63XX_CPU_6362 97 #define irq_stat_reg PERF_IRQSTAT_6362_REG 98 #define irq_mask_reg PERF_IRQMASK_6362_REG 99 #define irq_bits 64 100 #define is_ext_irq_cascaded 1 101 #define ext_irq_start (BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE) 102 #define ext_irq_end (BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE) 103 #define ext_irq_count 4 104 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6362 105 #define ext_irq_cfg_reg2 0 106 #endif 107 #ifdef CONFIG_BCM63XX_CPU_6368 108 #define irq_stat_reg PERF_IRQSTAT_6368_REG 109 #define irq_mask_reg PERF_IRQMASK_6368_REG 110 #define irq_bits 64 111 #define is_ext_irq_cascaded 1 112 #define ext_irq_start (BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE) 113 #define ext_irq_end (BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE) 114 #define ext_irq_count 6 115 #define ext_irq_cfg_reg1 PERF_EXTIRQ_CFG_REG_6368 116 #define ext_irq_cfg_reg2 PERF_EXTIRQ_CFG_REG2_6368 117 #endif 118 119 #if irq_bits == 32 120 #define dispatch_internal __dispatch_internal 121 #define internal_irq_mask __internal_irq_mask_32 122 #define internal_irq_unmask __internal_irq_unmask_32 123 #else 124 #define dispatch_internal __dispatch_internal_64 125 #define internal_irq_mask __internal_irq_mask_64 126 #define internal_irq_unmask __internal_irq_unmask_64 127 #endif 128 129 #define irq_stat_addr (bcm63xx_regset_address(RSET_PERF) + irq_stat_reg) 130 #define irq_mask_addr (bcm63xx_regset_address(RSET_PERF) + irq_mask_reg) 131 132 static inline void bcm63xx_init_irq(void) 133 { 134 } 135 #else /* ! BCMCPU_RUNTIME_DETECT */ 136 137 static u32 irq_stat_addr, irq_mask_addr; 138 static void (*dispatch_internal)(void); 139 static int is_ext_irq_cascaded; 140 static unsigned int ext_irq_count; 141 static unsigned int ext_irq_start, ext_irq_end; 142 static unsigned int ext_irq_cfg_reg1, ext_irq_cfg_reg2; 143 static void (*internal_irq_mask)(unsigned int irq); 144 static void (*internal_irq_unmask)(unsigned int irq); 145 146 static void bcm63xx_init_irq(void) 147 { 148 int irq_bits; 149 150 irq_stat_addr = bcm63xx_regset_address(RSET_PERF); 151 irq_mask_addr = bcm63xx_regset_address(RSET_PERF); 152 153 switch (bcm63xx_get_cpu_id()) { 154 case BCM3368_CPU_ID: 155 irq_stat_addr += PERF_IRQSTAT_3368_REG; 156 irq_mask_addr += PERF_IRQMASK_3368_REG; 157 irq_bits = 32; 158 ext_irq_count = 4; 159 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_3368; 160 break; 161 case BCM6328_CPU_ID: 162 irq_stat_addr += PERF_IRQSTAT_6328_REG; 163 irq_mask_addr += PERF_IRQMASK_6328_REG; 164 irq_bits = 64; 165 ext_irq_count = 4; 166 is_ext_irq_cascaded = 1; 167 ext_irq_start = BCM_6328_EXT_IRQ0 - IRQ_INTERNAL_BASE; 168 ext_irq_end = BCM_6328_EXT_IRQ3 - IRQ_INTERNAL_BASE; 169 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6328; 170 break; 171 case BCM6338_CPU_ID: 172 irq_stat_addr += PERF_IRQSTAT_6338_REG; 173 irq_mask_addr += PERF_IRQMASK_6338_REG; 174 irq_bits = 32; 175 ext_irq_count = 4; 176 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6338; 177 break; 178 case BCM6345_CPU_ID: 179 irq_stat_addr += PERF_IRQSTAT_6345_REG; 180 irq_mask_addr += PERF_IRQMASK_6345_REG; 181 irq_bits = 32; 182 ext_irq_count = 4; 183 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6345; 184 break; 185 case BCM6348_CPU_ID: 186 irq_stat_addr += PERF_IRQSTAT_6348_REG; 187 irq_mask_addr += PERF_IRQMASK_6348_REG; 188 irq_bits = 32; 189 ext_irq_count = 4; 190 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6348; 191 break; 192 case BCM6358_CPU_ID: 193 irq_stat_addr += PERF_IRQSTAT_6358_REG; 194 irq_mask_addr += PERF_IRQMASK_6358_REG; 195 irq_bits = 32; 196 ext_irq_count = 4; 197 is_ext_irq_cascaded = 1; 198 ext_irq_start = BCM_6358_EXT_IRQ0 - IRQ_INTERNAL_BASE; 199 ext_irq_end = BCM_6358_EXT_IRQ3 - IRQ_INTERNAL_BASE; 200 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6358; 201 break; 202 case BCM6362_CPU_ID: 203 irq_stat_addr += PERF_IRQSTAT_6362_REG; 204 irq_mask_addr += PERF_IRQMASK_6362_REG; 205 irq_bits = 64; 206 ext_irq_count = 4; 207 is_ext_irq_cascaded = 1; 208 ext_irq_start = BCM_6362_EXT_IRQ0 - IRQ_INTERNAL_BASE; 209 ext_irq_end = BCM_6362_EXT_IRQ3 - IRQ_INTERNAL_BASE; 210 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6362; 211 break; 212 case BCM6368_CPU_ID: 213 irq_stat_addr += PERF_IRQSTAT_6368_REG; 214 irq_mask_addr += PERF_IRQMASK_6368_REG; 215 irq_bits = 64; 216 ext_irq_count = 6; 217 is_ext_irq_cascaded = 1; 218 ext_irq_start = BCM_6368_EXT_IRQ0 - IRQ_INTERNAL_BASE; 219 ext_irq_end = BCM_6368_EXT_IRQ5 - IRQ_INTERNAL_BASE; 220 ext_irq_cfg_reg1 = PERF_EXTIRQ_CFG_REG_6368; 221 ext_irq_cfg_reg2 = PERF_EXTIRQ_CFG_REG2_6368; 222 break; 223 default: 224 BUG(); 225 } 226 227 if (irq_bits == 32) { 228 dispatch_internal = __dispatch_internal; 229 internal_irq_mask = __internal_irq_mask_32; 230 internal_irq_unmask = __internal_irq_unmask_32; 231 } else { 232 dispatch_internal = __dispatch_internal_64; 233 internal_irq_mask = __internal_irq_mask_64; 234 internal_irq_unmask = __internal_irq_unmask_64; 235 } 236 } 237 #endif /* ! BCMCPU_RUNTIME_DETECT */ 238 239 static inline u32 get_ext_irq_perf_reg(int irq) 240 { 241 if (irq < 4) 242 return ext_irq_cfg_reg1; 243 return ext_irq_cfg_reg2; 244 } 245 246 static inline void handle_internal(int intbit) 247 { 248 if (is_ext_irq_cascaded && 249 intbit >= ext_irq_start && intbit <= ext_irq_end) 250 do_IRQ(intbit - ext_irq_start + IRQ_EXTERNAL_BASE); 251 else 252 do_IRQ(intbit + IRQ_INTERNAL_BASE); 253 } 254 255 /* 256 * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not 257 * prioritize any interrupt relatively to another. the static counter 258 * will resume the loop where it ended the last time we left this 259 * function. 260 */ 261 static void __dispatch_internal(void) 262 { 263 u32 pending; 264 static int i; 265 266 pending = bcm_readl(irq_stat_addr) & bcm_readl(irq_mask_addr); 267 268 if (!pending) 269 return ; 270 271 while (1) { 272 int to_call = i; 273 274 i = (i + 1) & 0x1f; 275 if (pending & (1 << to_call)) { 276 handle_internal(to_call); 277 break; 278 } 279 } 280 } 281 282 static void __dispatch_internal_64(void) 283 { 284 u64 pending; 285 static int i; 286 287 pending = bcm_readq(irq_stat_addr) & bcm_readq(irq_mask_addr); 288 289 if (!pending) 290 return ; 291 292 while (1) { 293 int to_call = i; 294 295 i = (i + 1) & 0x3f; 296 if (pending & (1ull << to_call)) { 297 handle_internal(to_call); 298 break; 299 } 300 } 301 } 302 303 asmlinkage void plat_irq_dispatch(void) 304 { 305 u32 cause; 306 307 do { 308 cause = read_c0_cause() & read_c0_status() & ST0_IM; 309 310 if (!cause) 311 break; 312 313 if (cause & CAUSEF_IP7) 314 do_IRQ(7); 315 if (cause & CAUSEF_IP0) 316 do_IRQ(0); 317 if (cause & CAUSEF_IP1) 318 do_IRQ(1); 319 if (cause & CAUSEF_IP2) 320 dispatch_internal(); 321 if (!is_ext_irq_cascaded) { 322 if (cause & CAUSEF_IP3) 323 do_IRQ(IRQ_EXT_0); 324 if (cause & CAUSEF_IP4) 325 do_IRQ(IRQ_EXT_1); 326 if (cause & CAUSEF_IP5) 327 do_IRQ(IRQ_EXT_2); 328 if (cause & CAUSEF_IP6) 329 do_IRQ(IRQ_EXT_3); 330 } 331 } while (1); 332 } 333 334 /* 335 * internal IRQs operations: only mask/unmask on PERF irq mask 336 * register. 337 */ 338 static void __internal_irq_mask_32(unsigned int irq) 339 { 340 u32 mask; 341 342 mask = bcm_readl(irq_mask_addr); 343 mask &= ~(1 << irq); 344 bcm_writel(mask, irq_mask_addr); 345 } 346 347 static void __internal_irq_mask_64(unsigned int irq) 348 { 349 u64 mask; 350 351 mask = bcm_readq(irq_mask_addr); 352 mask &= ~(1ull << irq); 353 bcm_writeq(mask, irq_mask_addr); 354 } 355 356 static void __internal_irq_unmask_32(unsigned int irq) 357 { 358 u32 mask; 359 360 mask = bcm_readl(irq_mask_addr); 361 mask |= (1 << irq); 362 bcm_writel(mask, irq_mask_addr); 363 } 364 365 static void __internal_irq_unmask_64(unsigned int irq) 366 { 367 u64 mask; 368 369 mask = bcm_readq(irq_mask_addr); 370 mask |= (1ull << irq); 371 bcm_writeq(mask, irq_mask_addr); 372 } 373 374 static void bcm63xx_internal_irq_mask(struct irq_data *d) 375 { 376 internal_irq_mask(d->irq - IRQ_INTERNAL_BASE); 377 } 378 379 static void bcm63xx_internal_irq_unmask(struct irq_data *d) 380 { 381 internal_irq_unmask(d->irq - IRQ_INTERNAL_BASE); 382 } 383 384 /* 385 * external IRQs operations: mask/unmask and clear on PERF external 386 * irq control register. 387 */ 388 static void bcm63xx_external_irq_mask(struct irq_data *d) 389 { 390 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 391 u32 reg, regaddr; 392 393 regaddr = get_ext_irq_perf_reg(irq); 394 reg = bcm_perf_readl(regaddr); 395 396 if (BCMCPU_IS_6348()) 397 reg &= ~EXTIRQ_CFG_MASK_6348(irq % 4); 398 else 399 reg &= ~EXTIRQ_CFG_MASK(irq % 4); 400 401 bcm_perf_writel(reg, regaddr); 402 if (is_ext_irq_cascaded) 403 internal_irq_mask(irq + ext_irq_start); 404 } 405 406 static void bcm63xx_external_irq_unmask(struct irq_data *d) 407 { 408 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 409 u32 reg, regaddr; 410 411 regaddr = get_ext_irq_perf_reg(irq); 412 reg = bcm_perf_readl(regaddr); 413 414 if (BCMCPU_IS_6348()) 415 reg |= EXTIRQ_CFG_MASK_6348(irq % 4); 416 else 417 reg |= EXTIRQ_CFG_MASK(irq % 4); 418 419 bcm_perf_writel(reg, regaddr); 420 421 if (is_ext_irq_cascaded) 422 internal_irq_unmask(irq + ext_irq_start); 423 } 424 425 static void bcm63xx_external_irq_clear(struct irq_data *d) 426 { 427 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 428 u32 reg, regaddr; 429 430 regaddr = get_ext_irq_perf_reg(irq); 431 reg = bcm_perf_readl(regaddr); 432 433 if (BCMCPU_IS_6348()) 434 reg |= EXTIRQ_CFG_CLEAR_6348(irq % 4); 435 else 436 reg |= EXTIRQ_CFG_CLEAR(irq % 4); 437 438 bcm_perf_writel(reg, regaddr); 439 } 440 441 static int bcm63xx_external_irq_set_type(struct irq_data *d, 442 unsigned int flow_type) 443 { 444 unsigned int irq = d->irq - IRQ_EXTERNAL_BASE; 445 u32 reg, regaddr; 446 int levelsense, sense, bothedge; 447 448 flow_type &= IRQ_TYPE_SENSE_MASK; 449 450 if (flow_type == IRQ_TYPE_NONE) 451 flow_type = IRQ_TYPE_LEVEL_LOW; 452 453 levelsense = sense = bothedge = 0; 454 switch (flow_type) { 455 case IRQ_TYPE_EDGE_BOTH: 456 bothedge = 1; 457 break; 458 459 case IRQ_TYPE_EDGE_RISING: 460 sense = 1; 461 break; 462 463 case IRQ_TYPE_EDGE_FALLING: 464 break; 465 466 case IRQ_TYPE_LEVEL_HIGH: 467 levelsense = 1; 468 sense = 1; 469 break; 470 471 case IRQ_TYPE_LEVEL_LOW: 472 levelsense = 1; 473 break; 474 475 default: 476 printk(KERN_ERR "bogus flow type combination given !\n"); 477 return -EINVAL; 478 } 479 480 regaddr = get_ext_irq_perf_reg(irq); 481 reg = bcm_perf_readl(regaddr); 482 irq %= 4; 483 484 switch (bcm63xx_get_cpu_id()) { 485 case BCM6348_CPU_ID: 486 if (levelsense) 487 reg |= EXTIRQ_CFG_LEVELSENSE_6348(irq); 488 else 489 reg &= ~EXTIRQ_CFG_LEVELSENSE_6348(irq); 490 if (sense) 491 reg |= EXTIRQ_CFG_SENSE_6348(irq); 492 else 493 reg &= ~EXTIRQ_CFG_SENSE_6348(irq); 494 if (bothedge) 495 reg |= EXTIRQ_CFG_BOTHEDGE_6348(irq); 496 else 497 reg &= ~EXTIRQ_CFG_BOTHEDGE_6348(irq); 498 break; 499 500 case BCM3368_CPU_ID: 501 case BCM6328_CPU_ID: 502 case BCM6338_CPU_ID: 503 case BCM6345_CPU_ID: 504 case BCM6358_CPU_ID: 505 case BCM6362_CPU_ID: 506 case BCM6368_CPU_ID: 507 if (levelsense) 508 reg |= EXTIRQ_CFG_LEVELSENSE(irq); 509 else 510 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq); 511 if (sense) 512 reg |= EXTIRQ_CFG_SENSE(irq); 513 else 514 reg &= ~EXTIRQ_CFG_SENSE(irq); 515 if (bothedge) 516 reg |= EXTIRQ_CFG_BOTHEDGE(irq); 517 else 518 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq); 519 break; 520 default: 521 BUG(); 522 } 523 524 bcm_perf_writel(reg, regaddr); 525 526 irqd_set_trigger_type(d, flow_type); 527 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) 528 __irq_set_handler_locked(d->irq, handle_level_irq); 529 else 530 __irq_set_handler_locked(d->irq, handle_edge_irq); 531 532 return IRQ_SET_MASK_OK_NOCOPY; 533 } 534 535 static struct irq_chip bcm63xx_internal_irq_chip = { 536 .name = "bcm63xx_ipic", 537 .irq_mask = bcm63xx_internal_irq_mask, 538 .irq_unmask = bcm63xx_internal_irq_unmask, 539 }; 540 541 static struct irq_chip bcm63xx_external_irq_chip = { 542 .name = "bcm63xx_epic", 543 .irq_ack = bcm63xx_external_irq_clear, 544 545 .irq_mask = bcm63xx_external_irq_mask, 546 .irq_unmask = bcm63xx_external_irq_unmask, 547 548 .irq_set_type = bcm63xx_external_irq_set_type, 549 }; 550 551 static struct irqaction cpu_ip2_cascade_action = { 552 .handler = no_action, 553 .name = "cascade_ip2", 554 .flags = IRQF_NO_THREAD, 555 }; 556 557 static struct irqaction cpu_ext_cascade_action = { 558 .handler = no_action, 559 .name = "cascade_extirq", 560 .flags = IRQF_NO_THREAD, 561 }; 562 563 void __init arch_init_irq(void) 564 { 565 int i; 566 567 bcm63xx_init_irq(); 568 mips_cpu_irq_init(); 569 for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i) 570 irq_set_chip_and_handler(i, &bcm63xx_internal_irq_chip, 571 handle_level_irq); 572 573 for (i = IRQ_EXTERNAL_BASE; i < IRQ_EXTERNAL_BASE + ext_irq_count; ++i) 574 irq_set_chip_and_handler(i, &bcm63xx_external_irq_chip, 575 handle_edge_irq); 576 577 if (!is_ext_irq_cascaded) { 578 for (i = 3; i < 3 + ext_irq_count; ++i) 579 setup_irq(MIPS_CPU_IRQ_BASE + i, &cpu_ext_cascade_action); 580 } 581 582 setup_irq(MIPS_CPU_IRQ_BASE + 2, &cpu_ip2_cascade_action); 583 } 584