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