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