11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 31da177e4SLinus Torvalds * under the terms of the GNU General Public License as published by the 41da177e4SLinus Torvalds * Free Software Foundation; either version 2 of the License, or (at your 51da177e4SLinus Torvalds * option) any later version. 627f76819SRalf Baechle * 727f76819SRalf Baechle * Copyright (c) 2004 MIPS Inc 827f76819SRalf Baechle * Author: chris@mips.com 927f76819SRalf Baechle * 1027f76819SRalf Baechle * Copyright (C) 2004, 06 Ralf Baechle <ralf@linux-mips.org> 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds #include <linux/interrupt.h> 131da177e4SLinus Torvalds #include <linux/kernel.h> 141da177e4SLinus Torvalds #include <linux/sched.h> 151da177e4SLinus Torvalds #include <linux/kernel_stat.h> 161da177e4SLinus Torvalds #include <asm/io.h> 171da177e4SLinus Torvalds #include <asm/irq.h> 181da177e4SLinus Torvalds #include <asm/msc01_ic.h> 19411ba7fcSAtsushi Nemoto #include <asm/traps.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds static unsigned long _icctrl_msc; 221da177e4SLinus Torvalds #define MSC01_IC_REG_BASE _icctrl_msc 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds #define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0) 251da177e4SLinus Torvalds #define MSCIC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0) 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds static unsigned int irq_base; 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds /* mask off an interrupt */ 30e15883daSThomas Gleixner static inline void mask_msc_irq(struct irq_data *d) 311da177e4SLinus Torvalds { 32e15883daSThomas Gleixner unsigned int irq = d->irq; 33e15883daSThomas Gleixner 341da177e4SLinus Torvalds if (irq < (irq_base + 32)) 351da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); 361da177e4SLinus Torvalds else 371da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32)); 381da177e4SLinus Torvalds } 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds /* unmask an interrupt */ 41e15883daSThomas Gleixner static inline void unmask_msc_irq(struct irq_data *d) 421da177e4SLinus Torvalds { 43e15883daSThomas Gleixner unsigned int irq = d->irq; 44e15883daSThomas Gleixner 451da177e4SLinus Torvalds if (irq < (irq_base + 32)) 461da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); 471da177e4SLinus Torvalds else 481da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32)); 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds /* 521da177e4SLinus Torvalds * Masks and ACKs an IRQ 531da177e4SLinus Torvalds */ 54e15883daSThomas Gleixner static void level_mask_and_ack_msc_irq(struct irq_data *d) 551da177e4SLinus Torvalds { 56e15883daSThomas Gleixner mask_msc_irq(d); 57e01402b1SRalf Baechle if (!cpu_has_veic) 581da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds /* 621da177e4SLinus Torvalds * Masks and ACKs an IRQ 631da177e4SLinus Torvalds */ 64e15883daSThomas Gleixner static void edge_mask_and_ack_msc_irq(struct irq_data *d) 651da177e4SLinus Torvalds { 66e15883daSThomas Gleixner unsigned int irq = d->irq; 67e15883daSThomas Gleixner 68e15883daSThomas Gleixner mask_msc_irq(d); 69e01402b1SRalf Baechle if (!cpu_has_veic) 701da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 711da177e4SLinus Torvalds else { 721da177e4SLinus Torvalds u32 r; 731da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_SUP+irq*8, r); 741da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 751da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds /* 801da177e4SLinus Torvalds * Interrupt handler for interrupts coming from SOC-it. 811da177e4SLinus Torvalds */ 82937a8015SRalf Baechle void ll_msc_irq(void) 831da177e4SLinus Torvalds { 841da177e4SLinus Torvalds unsigned int irq; 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* read the interrupt vector register */ 871da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_VEC, irq); 881da177e4SLinus Torvalds if (irq < 64) 89937a8015SRalf Baechle do_IRQ(irq + irq_base); 901da177e4SLinus Torvalds else { 911da177e4SLinus Torvalds /* Ignore spurious interrupt */ 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 95411ba7fcSAtsushi Nemoto static void msc_bind_eic_interrupt(int irq, int set) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RAMW, 981da177e4SLinus Torvalds (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 101411ba7fcSAtsushi Nemoto static struct irq_chip msc_levelirq_type = { 10270d21cdeSAtsushi Nemoto .name = "SOC-it-Level", 103e15883daSThomas Gleixner .irq_ack = level_mask_and_ack_msc_irq, 104e15883daSThomas Gleixner .irq_mask = mask_msc_irq, 105e15883daSThomas Gleixner .irq_mask_ack = level_mask_and_ack_msc_irq, 106e15883daSThomas Gleixner .irq_unmask = unmask_msc_irq, 107e15883daSThomas Gleixner .irq_eoi = unmask_msc_irq, 1081da177e4SLinus Torvalds }; 1091da177e4SLinus Torvalds 110411ba7fcSAtsushi Nemoto static struct irq_chip msc_edgeirq_type = { 11170d21cdeSAtsushi Nemoto .name = "SOC-it-Edge", 112e15883daSThomas Gleixner .irq_ack = edge_mask_and_ack_msc_irq, 113e15883daSThomas Gleixner .irq_mask = mask_msc_irq, 114e15883daSThomas Gleixner .irq_mask_ack = edge_mask_and_ack_msc_irq, 115e15883daSThomas Gleixner .irq_unmask = unmask_msc_irq, 116e15883daSThomas Gleixner .irq_eoi = unmask_msc_irq, 1171da177e4SLinus Torvalds }; 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds 120d725cf38SChris Dearman void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq) 1211da177e4SLinus Torvalds { 122d725cf38SChris Dearman _icctrl_msc = (unsigned long) ioremap(icubase, 0x40000); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds /* Reset interrupt controller - initialises all registers to 0 */ 1251da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds board_bind_eic_interrupt = &msc_bind_eic_interrupt; 1281da177e4SLinus Torvalds 129*ab6c15bcSMarkos Chandras for (; nirq > 0; nirq--, imp++) { 1301da177e4SLinus Torvalds int n = imp->im_irq; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds switch (imp->im_type) { 1331da177e4SLinus Torvalds case MSC01_IRQ_EDGE: 134e4ec7989SThomas Gleixner irq_set_chip_and_handler_name(irqbase + n, 135e4ec7989SThomas Gleixner &msc_edgeirq_type, 136e4ec7989SThomas Gleixner handle_edge_irq, 137e4ec7989SThomas Gleixner "edge"); 138e01402b1SRalf Baechle if (cpu_has_veic) 1391da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 1401da177e4SLinus Torvalds else 1411da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 1421da177e4SLinus Torvalds break; 1431da177e4SLinus Torvalds case MSC01_IRQ_LEVEL: 144e4ec7989SThomas Gleixner irq_set_chip_and_handler_name(irqbase + n, 145e4ec7989SThomas Gleixner &msc_levelirq_type, 146e4ec7989SThomas Gleixner handle_level_irq, 147e4ec7989SThomas Gleixner "level"); 148e01402b1SRalf Baechle if (cpu_has_veic) 1491da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 1501da177e4SLinus Torvalds else 1511da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds } 1541da177e4SLinus Torvalds 155d725cf38SChris Dearman irq_base = irqbase; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds } 160