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. 6*27f76819SRalf Baechle * 7*27f76819SRalf Baechle * Copyright (c) 2004 MIPS Inc 8*27f76819SRalf Baechle * Author: chris@mips.com 9*27f76819SRalf Baechle * 10*27f76819SRalf 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 * Enables the IRQ on SOC-it 491da177e4SLinus Torvalds */ 501da177e4SLinus Torvalds static void enable_msc_irq(unsigned int irq) 511da177e4SLinus Torvalds { 521da177e4SLinus Torvalds unmask_msc_irq(irq); 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds /* 561da177e4SLinus Torvalds * Initialize the IRQ on SOC-it 571da177e4SLinus Torvalds */ 581da177e4SLinus Torvalds static unsigned int startup_msc_irq(unsigned int irq) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds unmask_msc_irq(irq); 611da177e4SLinus Torvalds return 0; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /* 651da177e4SLinus Torvalds * Disables the IRQ on SOC-it 661da177e4SLinus Torvalds */ 671da177e4SLinus Torvalds static void disable_msc_irq(unsigned int irq) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds mask_msc_irq(irq); 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds /* 731da177e4SLinus Torvalds * Masks and ACKs an IRQ 741da177e4SLinus Torvalds */ 751da177e4SLinus Torvalds static void level_mask_and_ack_msc_irq(unsigned int irq) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds mask_msc_irq(irq); 78e01402b1SRalf Baechle if (!cpu_has_veic) 791da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 8041c594abSRalf Baechle #ifdef CONFIG_MIPS_MT_SMTC 8141c594abSRalf Baechle /* This actually needs to be a call into platform code */ 8241c594abSRalf Baechle if (irq_hwmask[irq] & ST0_IM) 8341c594abSRalf Baechle set_c0_status(irq_hwmask[irq] & ST0_IM); 8441c594abSRalf Baechle #endif /* CONFIG_MIPS_MT_SMTC */ 851da177e4SLinus Torvalds } 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* 881da177e4SLinus Torvalds * Masks and ACKs an IRQ 891da177e4SLinus Torvalds */ 901da177e4SLinus Torvalds static void edge_mask_and_ack_msc_irq(unsigned int irq) 911da177e4SLinus Torvalds { 921da177e4SLinus Torvalds mask_msc_irq(irq); 93e01402b1SRalf Baechle if (!cpu_has_veic) 941da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 951da177e4SLinus Torvalds else { 961da177e4SLinus Torvalds u32 r; 971da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_SUP+irq*8, r); 981da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 991da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 1001da177e4SLinus Torvalds } 10141c594abSRalf Baechle #ifdef CONFIG_MIPS_MT_SMTC 10241c594abSRalf Baechle if (irq_hwmask[irq] & ST0_IM) 10341c594abSRalf Baechle set_c0_status(irq_hwmask[irq] & ST0_IM); 10441c594abSRalf Baechle #endif /* CONFIG_MIPS_MT_SMTC */ 1051da177e4SLinus Torvalds } 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /* 1081da177e4SLinus Torvalds * End IRQ processing 1091da177e4SLinus Torvalds */ 1101da177e4SLinus Torvalds static void end_msc_irq(unsigned int irq) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 1131da177e4SLinus Torvalds unmask_msc_irq(irq); 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds /* 1171da177e4SLinus Torvalds * Interrupt handler for interrupts coming from SOC-it. 1181da177e4SLinus Torvalds */ 119937a8015SRalf Baechle void ll_msc_irq(void) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds unsigned int irq; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds /* read the interrupt vector register */ 1241da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_VEC, irq); 1251da177e4SLinus Torvalds if (irq < 64) 126937a8015SRalf Baechle do_IRQ(irq + irq_base); 1271da177e4SLinus Torvalds else { 1281da177e4SLinus Torvalds /* Ignore spurious interrupt */ 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds } 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds void 1331da177e4SLinus Torvalds msc_bind_eic_interrupt (unsigned int irq, unsigned int set) 1341da177e4SLinus Torvalds { 1351da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RAMW, 1361da177e4SLinus Torvalds (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); 1371da177e4SLinus Torvalds } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds #define shutdown_msc_irq disable_msc_irq 1401da177e4SLinus Torvalds 14194dee171SRalf Baechle struct irq_chip msc_levelirq_type = { 1428ab00b9aSRalf Baechle .typename = "SOC-it-Level", 1438ab00b9aSRalf Baechle .startup = startup_msc_irq, 1448ab00b9aSRalf Baechle .shutdown = shutdown_msc_irq, 1458ab00b9aSRalf Baechle .enable = enable_msc_irq, 1468ab00b9aSRalf Baechle .disable = disable_msc_irq, 1478ab00b9aSRalf Baechle .ack = level_mask_and_ack_msc_irq, 1488ab00b9aSRalf Baechle .end = end_msc_irq, 1491da177e4SLinus Torvalds }; 1501da177e4SLinus Torvalds 15194dee171SRalf Baechle struct irq_chip msc_edgeirq_type = { 1528ab00b9aSRalf Baechle .typename = "SOC-it-Edge", 1538ab00b9aSRalf Baechle .startup =startup_msc_irq, 1548ab00b9aSRalf Baechle .shutdown = shutdown_msc_irq, 1558ab00b9aSRalf Baechle .enable = enable_msc_irq, 1568ab00b9aSRalf Baechle .disable = disable_msc_irq, 1578ab00b9aSRalf Baechle .ack = edge_mask_and_ack_msc_irq, 1588ab00b9aSRalf Baechle .end = end_msc_irq, 1591da177e4SLinus Torvalds }; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq) 1631da177e4SLinus Torvalds { 1641da177e4SLinus Torvalds extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds _icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000); 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds /* Reset interrupt controller - initialises all registers to 0 */ 1691da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds board_bind_eic_interrupt = &msc_bind_eic_interrupt; 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds for (; nirq >= 0; nirq--, imp++) { 1741da177e4SLinus Torvalds int n = imp->im_irq; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds switch (imp->im_type) { 1771da177e4SLinus Torvalds case MSC01_IRQ_EDGE: 178d1bef4edSIngo Molnar irq_desc[base+n].chip = &msc_edgeirq_type; 179e01402b1SRalf Baechle if (cpu_has_veic) 1801da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 1811da177e4SLinus Torvalds else 1821da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 1831da177e4SLinus Torvalds break; 1841da177e4SLinus Torvalds case MSC01_IRQ_LEVEL: 185d1bef4edSIngo Molnar irq_desc[base+n].chip = &msc_levelirq_type; 186e01402b1SRalf Baechle if (cpu_has_veic) 1871da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 1881da177e4SLinus Torvalds else 1891da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds irq_base = base; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds } 198