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