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> 20*411ba7fcSAtsushi Nemoto #include <asm/traps.h> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds static unsigned long _icctrl_msc; 231da177e4SLinus Torvalds #define MSC01_IC_REG_BASE _icctrl_msc 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0) 261da177e4SLinus Torvalds #define MSCIC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0) 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds static unsigned int irq_base; 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds /* mask off an interrupt */ 311da177e4SLinus Torvalds static inline void mask_msc_irq(unsigned int irq) 321da177e4SLinus Torvalds { 331da177e4SLinus Torvalds if (irq < (irq_base + 32)) 341da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); 351da177e4SLinus Torvalds else 361da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32)); 371da177e4SLinus Torvalds } 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds /* unmask an interrupt */ 401da177e4SLinus Torvalds static inline void unmask_msc_irq(unsigned int irq) 411da177e4SLinus Torvalds { 421da177e4SLinus Torvalds if (irq < (irq_base + 32)) 431da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); 441da177e4SLinus Torvalds else 451da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32)); 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* 491da177e4SLinus Torvalds * Masks and ACKs an IRQ 501da177e4SLinus Torvalds */ 511da177e4SLinus Torvalds static void level_mask_and_ack_msc_irq(unsigned int irq) 521da177e4SLinus Torvalds { 531da177e4SLinus Torvalds mask_msc_irq(irq); 54e01402b1SRalf Baechle if (!cpu_has_veic) 551da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 5641c594abSRalf Baechle /* This actually needs to be a call into platform code */ 571146fe30SRalf Baechle smtc_im_ack_irq(irq); 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds /* 611da177e4SLinus Torvalds * Masks and ACKs an IRQ 621da177e4SLinus Torvalds */ 631da177e4SLinus Torvalds static void edge_mask_and_ack_msc_irq(unsigned int irq) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds mask_msc_irq(irq); 66e01402b1SRalf Baechle if (!cpu_has_veic) 671da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 681da177e4SLinus Torvalds else { 691da177e4SLinus Torvalds u32 r; 701da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_SUP+irq*8, r); 711da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 721da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 731da177e4SLinus Torvalds } 741146fe30SRalf Baechle smtc_im_ack_irq(irq); 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds /* 781da177e4SLinus Torvalds * End IRQ processing 791da177e4SLinus Torvalds */ 801da177e4SLinus Torvalds static void end_msc_irq(unsigned int irq) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 831da177e4SLinus Torvalds unmask_msc_irq(irq); 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* 871da177e4SLinus Torvalds * Interrupt handler for interrupts coming from SOC-it. 881da177e4SLinus Torvalds */ 89937a8015SRalf Baechle void ll_msc_irq(void) 901da177e4SLinus Torvalds { 911da177e4SLinus Torvalds unsigned int irq; 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds /* read the interrupt vector register */ 941da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_VEC, irq); 951da177e4SLinus Torvalds if (irq < 64) 96937a8015SRalf Baechle do_IRQ(irq + irq_base); 971da177e4SLinus Torvalds else { 981da177e4SLinus Torvalds /* Ignore spurious interrupt */ 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds } 1011da177e4SLinus Torvalds 102*411ba7fcSAtsushi Nemoto static void msc_bind_eic_interrupt(int irq, int set) 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RAMW, 1051da177e4SLinus Torvalds (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 108*411ba7fcSAtsushi Nemoto static struct irq_chip msc_levelirq_type = { 10970d21cdeSAtsushi Nemoto .name = "SOC-it-Level", 1108ab00b9aSRalf Baechle .ack = level_mask_and_ack_msc_irq, 1111603b5acSAtsushi Nemoto .mask = mask_msc_irq, 1121603b5acSAtsushi Nemoto .mask_ack = level_mask_and_ack_msc_irq, 1131603b5acSAtsushi Nemoto .unmask = unmask_msc_irq, 1141417836eSAtsushi Nemoto .eoi = unmask_msc_irq, 1158ab00b9aSRalf Baechle .end = end_msc_irq, 1161da177e4SLinus Torvalds }; 1171da177e4SLinus Torvalds 118*411ba7fcSAtsushi Nemoto static struct irq_chip msc_edgeirq_type = { 11970d21cdeSAtsushi Nemoto .name = "SOC-it-Edge", 1208ab00b9aSRalf Baechle .ack = edge_mask_and_ack_msc_irq, 1211603b5acSAtsushi Nemoto .mask = mask_msc_irq, 1221603b5acSAtsushi Nemoto .mask_ack = edge_mask_and_ack_msc_irq, 1231603b5acSAtsushi Nemoto .unmask = unmask_msc_irq, 1241417836eSAtsushi Nemoto .eoi = unmask_msc_irq, 1258ab00b9aSRalf Baechle .end = end_msc_irq, 1261da177e4SLinus Torvalds }; 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds 129d725cf38SChris Dearman void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqmap_t *imp, int nirq) 1301da177e4SLinus Torvalds { 131d725cf38SChris Dearman _icctrl_msc = (unsigned long) ioremap(icubase, 0x40000); 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds /* Reset interrupt controller - initialises all registers to 0 */ 1341da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds board_bind_eic_interrupt = &msc_bind_eic_interrupt; 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds for (; nirq >= 0; nirq--, imp++) { 1391da177e4SLinus Torvalds int n = imp->im_irq; 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds switch (imp->im_type) { 1421da177e4SLinus Torvalds case MSC01_IRQ_EDGE: 143d725cf38SChris Dearman set_irq_chip(irqbase+n, &msc_edgeirq_type); 144e01402b1SRalf Baechle if (cpu_has_veic) 1451da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 1461da177e4SLinus Torvalds else 1471da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 1481da177e4SLinus Torvalds break; 1491da177e4SLinus Torvalds case MSC01_IRQ_LEVEL: 150d725cf38SChris Dearman set_irq_chip(irqbase+n, &msc_levelirq_type); 151e01402b1SRalf Baechle if (cpu_has_veic) 1521da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 1531da177e4SLinus Torvalds else 1541da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 158d725cf38SChris Dearman irq_base = irqbase; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds } 163