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