11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright (c) 2004 MIPS Inc 31da177e4SLinus Torvalds * Author: chris@mips.com 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 61da177e4SLinus Torvalds * under the terms of the GNU General Public License as published by the 71da177e4SLinus Torvalds * Free Software Foundation; either version 2 of the License, or (at your 81da177e4SLinus Torvalds * option) any later version. 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds #include <linux/module.h> 111da177e4SLinus Torvalds #include <linux/interrupt.h> 121da177e4SLinus Torvalds #include <linux/kernel.h> 131da177e4SLinus Torvalds #include <asm/ptrace.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> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds static unsigned long _icctrl_msc; 211da177e4SLinus Torvalds #define MSC01_IC_REG_BASE _icctrl_msc 221da177e4SLinus Torvalds 231da177e4SLinus Torvalds #define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0) 241da177e4SLinus Torvalds #define MSCIC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0) 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds static unsigned int irq_base; 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* mask off an interrupt */ 291da177e4SLinus Torvalds static inline void mask_msc_irq(unsigned int irq) 301da177e4SLinus Torvalds { 311da177e4SLinus Torvalds if (irq < (irq_base + 32)) 321da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); 331da177e4SLinus Torvalds else 341da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32)); 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds /* unmask an interrupt */ 381da177e4SLinus Torvalds static inline void unmask_msc_irq(unsigned int irq) 391da177e4SLinus Torvalds { 401da177e4SLinus Torvalds if (irq < (irq_base + 32)) 411da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); 421da177e4SLinus Torvalds else 431da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32)); 441da177e4SLinus Torvalds } 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds /* 471da177e4SLinus Torvalds * Enables the IRQ on SOC-it 481da177e4SLinus Torvalds */ 491da177e4SLinus Torvalds static void enable_msc_irq(unsigned int irq) 501da177e4SLinus Torvalds { 511da177e4SLinus Torvalds unmask_msc_irq(irq); 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* 551da177e4SLinus Torvalds * Initialize the IRQ on SOC-it 561da177e4SLinus Torvalds */ 571da177e4SLinus Torvalds static unsigned int startup_msc_irq(unsigned int irq) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds unmask_msc_irq(irq); 601da177e4SLinus Torvalds return 0; 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds /* 641da177e4SLinus Torvalds * Disables the IRQ on SOC-it 651da177e4SLinus Torvalds */ 661da177e4SLinus Torvalds static void disable_msc_irq(unsigned int irq) 671da177e4SLinus Torvalds { 681da177e4SLinus Torvalds mask_msc_irq(irq); 691da177e4SLinus Torvalds } 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds /* 721da177e4SLinus Torvalds * Masks and ACKs an IRQ 731da177e4SLinus Torvalds */ 741da177e4SLinus Torvalds static void level_mask_and_ack_msc_irq(unsigned int irq) 751da177e4SLinus Torvalds { 761da177e4SLinus Torvalds mask_msc_irq(irq); 77e01402b1SRalf Baechle if (!cpu_has_veic) 781da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 7941c594abSRalf Baechle #ifdef CONFIG_MIPS_MT_SMTC 8041c594abSRalf Baechle /* This actually needs to be a call into platform code */ 8141c594abSRalf Baechle if (irq_hwmask[irq] & ST0_IM) 8241c594abSRalf Baechle set_c0_status(irq_hwmask[irq] & ST0_IM); 8341c594abSRalf Baechle #endif /* CONFIG_MIPS_MT_SMTC */ 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* 871da177e4SLinus Torvalds * Masks and ACKs an IRQ 881da177e4SLinus Torvalds */ 891da177e4SLinus Torvalds static void edge_mask_and_ack_msc_irq(unsigned int irq) 901da177e4SLinus Torvalds { 911da177e4SLinus Torvalds mask_msc_irq(irq); 92e01402b1SRalf Baechle if (!cpu_has_veic) 931da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 941da177e4SLinus Torvalds else { 951da177e4SLinus Torvalds u32 r; 961da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_SUP+irq*8, r); 971da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 981da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 991da177e4SLinus Torvalds } 10041c594abSRalf Baechle #ifdef CONFIG_MIPS_MT_SMTC 10141c594abSRalf Baechle if (irq_hwmask[irq] & ST0_IM) 10241c594abSRalf Baechle set_c0_status(irq_hwmask[irq] & ST0_IM); 10341c594abSRalf Baechle #endif /* CONFIG_MIPS_MT_SMTC */ 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* 1071da177e4SLinus Torvalds * End IRQ processing 1081da177e4SLinus Torvalds */ 1091da177e4SLinus Torvalds static void end_msc_irq(unsigned int irq) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 1121da177e4SLinus Torvalds unmask_msc_irq(irq); 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds /* 1161da177e4SLinus Torvalds * Interrupt handler for interrupts coming from SOC-it. 1171da177e4SLinus Torvalds */ 1181da177e4SLinus Torvalds void ll_msc_irq(struct pt_regs *regs) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds unsigned int irq; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* read the interrupt vector register */ 1231da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_VEC, irq); 1241da177e4SLinus Torvalds if (irq < 64) 1251da177e4SLinus Torvalds do_IRQ(irq + irq_base, regs); 1261da177e4SLinus Torvalds else { 1271da177e4SLinus Torvalds /* Ignore spurious interrupt */ 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds void 1321da177e4SLinus Torvalds msc_bind_eic_interrupt (unsigned int irq, unsigned int set) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RAMW, 1351da177e4SLinus Torvalds (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds #define shutdown_msc_irq disable_msc_irq 1391da177e4SLinus Torvalds 140*94dee171SRalf Baechle struct irq_chip msc_levelirq_type = { 1418ab00b9aSRalf Baechle .typename = "SOC-it-Level", 1428ab00b9aSRalf Baechle .startup = startup_msc_irq, 1438ab00b9aSRalf Baechle .shutdown = shutdown_msc_irq, 1448ab00b9aSRalf Baechle .enable = enable_msc_irq, 1458ab00b9aSRalf Baechle .disable = disable_msc_irq, 1468ab00b9aSRalf Baechle .ack = level_mask_and_ack_msc_irq, 1478ab00b9aSRalf Baechle .end = end_msc_irq, 1481da177e4SLinus Torvalds }; 1491da177e4SLinus Torvalds 150*94dee171SRalf Baechle struct irq_chip msc_edgeirq_type = { 1518ab00b9aSRalf Baechle .typename = "SOC-it-Edge", 1528ab00b9aSRalf Baechle .startup =startup_msc_irq, 1538ab00b9aSRalf Baechle .shutdown = shutdown_msc_irq, 1548ab00b9aSRalf Baechle .enable = enable_msc_irq, 1558ab00b9aSRalf Baechle .disable = disable_msc_irq, 1568ab00b9aSRalf Baechle .ack = edge_mask_and_ack_msc_irq, 1578ab00b9aSRalf Baechle .end = end_msc_irq, 1581da177e4SLinus Torvalds }; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq) 1621da177e4SLinus Torvalds { 1631da177e4SLinus Torvalds extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset); 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds _icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* Reset interrupt controller - initialises all registers to 0 */ 1681da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds board_bind_eic_interrupt = &msc_bind_eic_interrupt; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds for (; nirq >= 0; nirq--, imp++) { 1731da177e4SLinus Torvalds int n = imp->im_irq; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds switch (imp->im_type) { 1761da177e4SLinus Torvalds case MSC01_IRQ_EDGE: 177d1bef4edSIngo Molnar irq_desc[base+n].chip = &msc_edgeirq_type; 178e01402b1SRalf Baechle if (cpu_has_veic) 1791da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 1801da177e4SLinus Torvalds else 1811da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 1821da177e4SLinus Torvalds break; 1831da177e4SLinus Torvalds case MSC01_IRQ_LEVEL: 184d1bef4edSIngo Molnar irq_desc[base+n].chip = &msc_levelirq_type; 185e01402b1SRalf Baechle if (cpu_has_veic) 1861da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 1871da177e4SLinus Torvalds else 1881da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds irq_base = base; 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds } 197