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/module.h> 131da177e4SLinus Torvalds #include <linux/interrupt.h> 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/sched.h> 161da177e4SLinus Torvalds #include <linux/kernel_stat.h> 171da177e4SLinus Torvalds #include <asm/io.h> 181da177e4SLinus Torvalds #include <asm/irq.h> 191da177e4SLinus Torvalds #include <asm/msc01_ic.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 */ 301da177e4SLinus Torvalds static inline void mask_msc_irq(unsigned int irq) 311da177e4SLinus Torvalds { 321da177e4SLinus Torvalds if (irq < (irq_base + 32)) 331da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); 341da177e4SLinus Torvalds else 351da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32)); 361da177e4SLinus Torvalds } 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* unmask an interrupt */ 391da177e4SLinus Torvalds static inline void unmask_msc_irq(unsigned int irq) 401da177e4SLinus Torvalds { 411da177e4SLinus Torvalds if (irq < (irq_base + 32)) 421da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); 431da177e4SLinus Torvalds else 441da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32)); 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /* 481da177e4SLinus Torvalds * Masks and ACKs an IRQ 491da177e4SLinus Torvalds */ 501da177e4SLinus Torvalds static void level_mask_and_ack_msc_irq(unsigned int irq) 511da177e4SLinus Torvalds { 521da177e4SLinus Torvalds mask_msc_irq(irq); 53e01402b1SRalf Baechle if (!cpu_has_veic) 541da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 5541c594abSRalf Baechle #ifdef CONFIG_MIPS_MT_SMTC 5641c594abSRalf Baechle /* This actually needs to be a call into platform code */ 5741c594abSRalf Baechle if (irq_hwmask[irq] & ST0_IM) 5841c594abSRalf Baechle set_c0_status(irq_hwmask[irq] & ST0_IM); 5941c594abSRalf Baechle #endif /* CONFIG_MIPS_MT_SMTC */ 601da177e4SLinus Torvalds } 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds /* 631da177e4SLinus Torvalds * Masks and ACKs an IRQ 641da177e4SLinus Torvalds */ 651da177e4SLinus Torvalds static void edge_mask_and_ack_msc_irq(unsigned int irq) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds mask_msc_irq(irq); 68e01402b1SRalf Baechle if (!cpu_has_veic) 691da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 701da177e4SLinus Torvalds else { 711da177e4SLinus Torvalds u32 r; 721da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_SUP+irq*8, r); 731da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 741da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 751da177e4SLinus Torvalds } 7641c594abSRalf Baechle #ifdef CONFIG_MIPS_MT_SMTC 7741c594abSRalf Baechle if (irq_hwmask[irq] & ST0_IM) 7841c594abSRalf Baechle set_c0_status(irq_hwmask[irq] & ST0_IM); 7941c594abSRalf Baechle #endif /* CONFIG_MIPS_MT_SMTC */ 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds /* 831da177e4SLinus Torvalds * End IRQ processing 841da177e4SLinus Torvalds */ 851da177e4SLinus Torvalds static void end_msc_irq(unsigned int irq) 861da177e4SLinus Torvalds { 871da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 881da177e4SLinus Torvalds unmask_msc_irq(irq); 891da177e4SLinus Torvalds } 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds /* 921da177e4SLinus Torvalds * Interrupt handler for interrupts coming from SOC-it. 931da177e4SLinus Torvalds */ 94937a8015SRalf Baechle void ll_msc_irq(void) 951da177e4SLinus Torvalds { 961da177e4SLinus Torvalds unsigned int irq; 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds /* read the interrupt vector register */ 991da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_VEC, irq); 1001da177e4SLinus Torvalds if (irq < 64) 101937a8015SRalf Baechle do_IRQ(irq + irq_base); 1021da177e4SLinus Torvalds else { 1031da177e4SLinus Torvalds /* Ignore spurious interrupt */ 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds void 1081da177e4SLinus Torvalds msc_bind_eic_interrupt (unsigned int irq, unsigned int set) 1091da177e4SLinus Torvalds { 1101da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RAMW, 1111da177e4SLinus Torvalds (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 11494dee171SRalf Baechle struct irq_chip msc_levelirq_type = { 115*70d21cdeSAtsushi Nemoto .name = "SOC-it-Level", 1168ab00b9aSRalf Baechle .ack = level_mask_and_ack_msc_irq, 1171603b5acSAtsushi Nemoto .mask = mask_msc_irq, 1181603b5acSAtsushi Nemoto .mask_ack = level_mask_and_ack_msc_irq, 1191603b5acSAtsushi Nemoto .unmask = unmask_msc_irq, 1201417836eSAtsushi Nemoto .eoi = unmask_msc_irq, 1218ab00b9aSRalf Baechle .end = end_msc_irq, 1221da177e4SLinus Torvalds }; 1231da177e4SLinus Torvalds 12494dee171SRalf Baechle struct irq_chip msc_edgeirq_type = { 125*70d21cdeSAtsushi Nemoto .name = "SOC-it-Edge", 1268ab00b9aSRalf Baechle .ack = edge_mask_and_ack_msc_irq, 1271603b5acSAtsushi Nemoto .mask = mask_msc_irq, 1281603b5acSAtsushi Nemoto .mask_ack = edge_mask_and_ack_msc_irq, 1291603b5acSAtsushi Nemoto .unmask = unmask_msc_irq, 1301417836eSAtsushi Nemoto .eoi = unmask_msc_irq, 1318ab00b9aSRalf Baechle .end = end_msc_irq, 1321da177e4SLinus Torvalds }; 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq) 1361da177e4SLinus Torvalds { 1371da177e4SLinus Torvalds extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset); 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds _icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000); 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* Reset interrupt controller - initialises all registers to 0 */ 1421da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds board_bind_eic_interrupt = &msc_bind_eic_interrupt; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds for (; nirq >= 0; nirq--, imp++) { 1471da177e4SLinus Torvalds int n = imp->im_irq; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds switch (imp->im_type) { 1501da177e4SLinus Torvalds case MSC01_IRQ_EDGE: 1511603b5acSAtsushi Nemoto set_irq_chip(base+n, &msc_edgeirq_type); 152e01402b1SRalf Baechle if (cpu_has_veic) 1531da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 1541da177e4SLinus Torvalds else 1551da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 1561da177e4SLinus Torvalds break; 1571da177e4SLinus Torvalds case MSC01_IRQ_LEVEL: 1581603b5acSAtsushi Nemoto set_irq_chip(base+n, &msc_levelirq_type); 159e01402b1SRalf Baechle if (cpu_has_veic) 1601da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 1611da177e4SLinus Torvalds else 1621da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); 1631da177e4SLinus Torvalds } 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds irq_base = base; 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds } 171