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