1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Copyright (c) 2004 MIPS Inc 3*1da177e4SLinus Torvalds * Author: chris@mips.com 4*1da177e4SLinus Torvalds * 5*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 6*1da177e4SLinus Torvalds * under the terms of the GNU General Public License as published by the 7*1da177e4SLinus Torvalds * Free Software Foundation; either version 2 of the License, or (at your 8*1da177e4SLinus Torvalds * option) any later version. 9*1da177e4SLinus Torvalds */ 10*1da177e4SLinus Torvalds #include <linux/module.h> 11*1da177e4SLinus Torvalds #include <linux/interrupt.h> 12*1da177e4SLinus Torvalds #include <linux/kernel.h> 13*1da177e4SLinus Torvalds #include <asm/ptrace.h> 14*1da177e4SLinus Torvalds #include <linux/sched.h> 15*1da177e4SLinus Torvalds #include <linux/kernel_stat.h> 16*1da177e4SLinus Torvalds #include <asm/io.h> 17*1da177e4SLinus Torvalds #include <asm/irq.h> 18*1da177e4SLinus Torvalds #include <asm/msc01_ic.h> 19*1da177e4SLinus Torvalds 20*1da177e4SLinus Torvalds static unsigned long _icctrl_msc; 21*1da177e4SLinus Torvalds #define MSC01_IC_REG_BASE _icctrl_msc 22*1da177e4SLinus Torvalds 23*1da177e4SLinus Torvalds #define MSCIC_WRITE(reg, data) do { *(volatile u32 *)(reg) = data; } while (0) 24*1da177e4SLinus Torvalds #define MSCIC_READ(reg, data) do { data = *(volatile u32 *)(reg); } while (0) 25*1da177e4SLinus Torvalds 26*1da177e4SLinus Torvalds static unsigned int irq_base; 27*1da177e4SLinus Torvalds 28*1da177e4SLinus Torvalds /* mask off an interrupt */ 29*1da177e4SLinus Torvalds static inline void mask_msc_irq(unsigned int irq) 30*1da177e4SLinus Torvalds { 31*1da177e4SLinus Torvalds if (irq < (irq_base + 32)) 32*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); 33*1da177e4SLinus Torvalds else 34*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_DISH, 1<<(irq - irq_base - 32)); 35*1da177e4SLinus Torvalds } 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds /* unmask an interrupt */ 38*1da177e4SLinus Torvalds static inline void unmask_msc_irq(unsigned int irq) 39*1da177e4SLinus Torvalds { 40*1da177e4SLinus Torvalds if (irq < (irq_base + 32)) 41*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); 42*1da177e4SLinus Torvalds else 43*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_ENAH, 1<<(irq - irq_base - 32)); 44*1da177e4SLinus Torvalds } 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds /* 47*1da177e4SLinus Torvalds * Enables the IRQ on SOC-it 48*1da177e4SLinus Torvalds */ 49*1da177e4SLinus Torvalds static void enable_msc_irq(unsigned int irq) 50*1da177e4SLinus Torvalds { 51*1da177e4SLinus Torvalds unmask_msc_irq(irq); 52*1da177e4SLinus Torvalds } 53*1da177e4SLinus Torvalds 54*1da177e4SLinus Torvalds /* 55*1da177e4SLinus Torvalds * Initialize the IRQ on SOC-it 56*1da177e4SLinus Torvalds */ 57*1da177e4SLinus Torvalds static unsigned int startup_msc_irq(unsigned int irq) 58*1da177e4SLinus Torvalds { 59*1da177e4SLinus Torvalds unmask_msc_irq(irq); 60*1da177e4SLinus Torvalds return 0; 61*1da177e4SLinus Torvalds } 62*1da177e4SLinus Torvalds 63*1da177e4SLinus Torvalds /* 64*1da177e4SLinus Torvalds * Disables the IRQ on SOC-it 65*1da177e4SLinus Torvalds */ 66*1da177e4SLinus Torvalds static void disable_msc_irq(unsigned int irq) 67*1da177e4SLinus Torvalds { 68*1da177e4SLinus Torvalds mask_msc_irq(irq); 69*1da177e4SLinus Torvalds } 70*1da177e4SLinus Torvalds 71*1da177e4SLinus Torvalds /* 72*1da177e4SLinus Torvalds * Masks and ACKs an IRQ 73*1da177e4SLinus Torvalds */ 74*1da177e4SLinus Torvalds static void level_mask_and_ack_msc_irq(unsigned int irq) 75*1da177e4SLinus Torvalds { 76*1da177e4SLinus Torvalds mask_msc_irq(irq); 77*1da177e4SLinus Torvalds if (!cpu_has_ei) 78*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 79*1da177e4SLinus Torvalds } 80*1da177e4SLinus Torvalds 81*1da177e4SLinus Torvalds /* 82*1da177e4SLinus Torvalds * Masks and ACKs an IRQ 83*1da177e4SLinus Torvalds */ 84*1da177e4SLinus Torvalds static void edge_mask_and_ack_msc_irq(unsigned int irq) 85*1da177e4SLinus Torvalds { 86*1da177e4SLinus Torvalds mask_msc_irq(irq); 87*1da177e4SLinus Torvalds if (!cpu_has_ei) 88*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_EOI, 0); 89*1da177e4SLinus Torvalds else { 90*1da177e4SLinus Torvalds u32 r; 91*1da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_SUP+irq*8, r); 92*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r | ~MSC01_IC_SUP_EDGE_BIT); 93*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+irq*8, r); 94*1da177e4SLinus Torvalds } 95*1da177e4SLinus Torvalds } 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds /* 98*1da177e4SLinus Torvalds * End IRQ processing 99*1da177e4SLinus Torvalds */ 100*1da177e4SLinus Torvalds static void end_msc_irq(unsigned int irq) 101*1da177e4SLinus Torvalds { 102*1da177e4SLinus Torvalds if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 103*1da177e4SLinus Torvalds unmask_msc_irq(irq); 104*1da177e4SLinus Torvalds } 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds /* 107*1da177e4SLinus Torvalds * Interrupt handler for interrupts coming from SOC-it. 108*1da177e4SLinus Torvalds */ 109*1da177e4SLinus Torvalds void ll_msc_irq(struct pt_regs *regs) 110*1da177e4SLinus Torvalds { 111*1da177e4SLinus Torvalds unsigned int irq; 112*1da177e4SLinus Torvalds 113*1da177e4SLinus Torvalds /* read the interrupt vector register */ 114*1da177e4SLinus Torvalds MSCIC_READ(MSC01_IC_VEC, irq); 115*1da177e4SLinus Torvalds if (irq < 64) 116*1da177e4SLinus Torvalds do_IRQ(irq + irq_base, regs); 117*1da177e4SLinus Torvalds else { 118*1da177e4SLinus Torvalds /* Ignore spurious interrupt */ 119*1da177e4SLinus Torvalds } 120*1da177e4SLinus Torvalds } 121*1da177e4SLinus Torvalds 122*1da177e4SLinus Torvalds void 123*1da177e4SLinus Torvalds msc_bind_eic_interrupt (unsigned int irq, unsigned int set) 124*1da177e4SLinus Torvalds { 125*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RAMW, 126*1da177e4SLinus Torvalds (irq<<MSC01_IC_RAMW_ADDR_SHF) | (set<<MSC01_IC_RAMW_DATA_SHF)); 127*1da177e4SLinus Torvalds } 128*1da177e4SLinus Torvalds 129*1da177e4SLinus Torvalds #define shutdown_msc_irq disable_msc_irq 130*1da177e4SLinus Torvalds 131*1da177e4SLinus Torvalds struct hw_interrupt_type msc_levelirq_type = { 132*1da177e4SLinus Torvalds "SOC-it-Level", 133*1da177e4SLinus Torvalds startup_msc_irq, 134*1da177e4SLinus Torvalds shutdown_msc_irq, 135*1da177e4SLinus Torvalds enable_msc_irq, 136*1da177e4SLinus Torvalds disable_msc_irq, 137*1da177e4SLinus Torvalds level_mask_and_ack_msc_irq, 138*1da177e4SLinus Torvalds end_msc_irq, 139*1da177e4SLinus Torvalds NULL 140*1da177e4SLinus Torvalds }; 141*1da177e4SLinus Torvalds 142*1da177e4SLinus Torvalds struct hw_interrupt_type msc_edgeirq_type = { 143*1da177e4SLinus Torvalds "SOC-it-Edge", 144*1da177e4SLinus Torvalds startup_msc_irq, 145*1da177e4SLinus Torvalds shutdown_msc_irq, 146*1da177e4SLinus Torvalds enable_msc_irq, 147*1da177e4SLinus Torvalds disable_msc_irq, 148*1da177e4SLinus Torvalds edge_mask_and_ack_msc_irq, 149*1da177e4SLinus Torvalds end_msc_irq, 150*1da177e4SLinus Torvalds NULL 151*1da177e4SLinus Torvalds }; 152*1da177e4SLinus Torvalds 153*1da177e4SLinus Torvalds 154*1da177e4SLinus Torvalds void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq) 155*1da177e4SLinus Torvalds { 156*1da177e4SLinus Torvalds extern void (*board_bind_eic_interrupt)(unsigned int irq, unsigned int regset); 157*1da177e4SLinus Torvalds 158*1da177e4SLinus Torvalds _icctrl_msc = (unsigned long) ioremap (MIPS_MSC01_IC_REG_BASE, 0x40000); 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds /* Reset interrupt controller - initialises all registers to 0 */ 161*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_RST, MSC01_IC_RST_RST_BIT); 162*1da177e4SLinus Torvalds 163*1da177e4SLinus Torvalds board_bind_eic_interrupt = &msc_bind_eic_interrupt; 164*1da177e4SLinus Torvalds 165*1da177e4SLinus Torvalds for (; nirq >= 0; nirq--, imp++) { 166*1da177e4SLinus Torvalds int n = imp->im_irq; 167*1da177e4SLinus Torvalds 168*1da177e4SLinus Torvalds switch (imp->im_type) { 169*1da177e4SLinus Torvalds case MSC01_IRQ_EDGE: 170*1da177e4SLinus Torvalds irq_desc[base+n].handler = &msc_edgeirq_type; 171*1da177e4SLinus Torvalds if (cpu_has_ei) 172*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); 173*1da177e4SLinus Torvalds else 174*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); 175*1da177e4SLinus Torvalds break; 176*1da177e4SLinus Torvalds case MSC01_IRQ_LEVEL: 177*1da177e4SLinus Torvalds irq_desc[base+n].handler = &msc_levelirq_type; 178*1da177e4SLinus Torvalds if (cpu_has_ei) 179*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); 180*1da177e4SLinus Torvalds else 181*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_SUP+n*8, imp->im_lvl); 182*1da177e4SLinus Torvalds } 183*1da177e4SLinus Torvalds } 184*1da177e4SLinus Torvalds 185*1da177e4SLinus Torvalds irq_base = base; 186*1da177e4SLinus Torvalds 187*1da177e4SLinus Torvalds MSCIC_WRITE(MSC01_IC_GENA, MSC01_IC_GENA_GENA_BIT); /* Enable interrupt generation */ 188*1da177e4SLinus Torvalds 189*1da177e4SLinus Torvalds } 190