1/* 2 * File: arch/blackfin/mach-common/interrupt.S 3 * Based on: 4 * Author: D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca> 5 * Kenneth Albanowski <kjahds@kjahds.com> 6 * 7 * Created: ? 8 * Description: Interrupt Entries 9 * 10 * Modified: 11 * Copyright 2004-2006 Analog Devices Inc. 12 * 13 * Bugs: Enter bugs at http://blackfin.uclinux.org/ 14 * 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License as published by 17 * the Free Software Foundation; either version 2 of the License, or 18 * (at your option) any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public License 26 * along with this program; if not, see the file COPYING, or write 27 * to the Free Software Foundation, Inc., 28 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 */ 30 31#include <asm/blackfin.h> 32#include <asm/mach/irq.h> 33#include <linux/autoconf.h> 34#include <linux/linkage.h> 35#include <asm/entry.h> 36#include <asm/asm-offsets.h> 37 38#include <asm/mach-common/context.S> 39 40#ifdef CONFIG_I_ENTRY_L1 41.section .l1.text 42#else 43.text 44#endif 45 46.align 4 /* just in case */ 47 48/* 49 * initial interrupt handlers 50 */ 51 52#ifndef CONFIG_KGDB 53 /* interrupt routine for emulation - 0 */ 54 /* Currently used only if GDB stub is not in - invalid */ 55 /* gdb-stub set the evt itself */ 56 /* save registers for post-mortem only */ 57ENTRY(_evt_emulation) 58 SAVE_ALL_SYS 59#ifdef CONFIG_FRAME_POINTER 60 fp = 0; 61#endif 62 r0 = IRQ_EMU; 63 r1 = sp; 64 SP += -12; 65 call _irq_panic; 66 SP += 12; 67 /* - GDB stub fills this in by itself (if defined) */ 68 rte; 69ENDPROC(_evt_emulation) 70#endif 71 72/* Common interrupt entry code. First we do CLI, then push 73 * RETI, to keep interrupts disabled, but to allow this state to be changed 74 * by local_bh_enable. 75 * R0 contains the interrupt number, while R1 may contain the value of IPEND, 76 * or garbage if IPEND won't be needed by the ISR. */ 77__common_int_entry: 78 [--sp] = fp; 79 [--sp] = usp; 80 81 [--sp] = i0; 82 [--sp] = i1; 83 [--sp] = i2; 84 [--sp] = i3; 85 86 [--sp] = m0; 87 [--sp] = m1; 88 [--sp] = m2; 89 [--sp] = m3; 90 91 [--sp] = l0; 92 [--sp] = l1; 93 [--sp] = l2; 94 [--sp] = l3; 95 96 [--sp] = b0; 97 [--sp] = b1; 98 [--sp] = b2; 99 [--sp] = b3; 100 [--sp] = a0.x; 101 [--sp] = a0.w; 102 [--sp] = a1.x; 103 [--sp] = a1.w; 104 105 [--sp] = LC0; 106 [--sp] = LC1; 107 [--sp] = LT0; 108 [--sp] = LT1; 109 [--sp] = LB0; 110 [--sp] = LB1; 111 112 [--sp] = ASTAT; 113 114 [--sp] = r0; /* Skip reserved */ 115 [--sp] = RETS; 116 r2 = RETI; 117 [--sp] = r2; 118 [--sp] = RETX; 119 [--sp] = RETN; 120 [--sp] = RETE; 121 [--sp] = SEQSTAT; 122 [--sp] = r1; /* IPEND - R1 may or may not be set up before jumping here. */ 123 124 /* Switch to other method of keeping interrupts disabled. */ 125#ifdef CONFIG_DEBUG_HWERR 126 r1 = 0x3f; 127 sti r1; 128#else 129 cli r1; 130#endif 131 [--sp] = RETI; /* orig_pc */ 132 /* Clear all L registers. */ 133 r1 = 0 (x); 134 l0 = r1; 135 l1 = r1; 136 l2 = r1; 137 l3 = r1; 138#ifdef CONFIG_FRAME_POINTER 139 fp = 0; 140#endif 141 142#if defined(ANOMALY_05000283) || defined(ANOMALY_05000315) 143 cc = r7 == r7; 144 p5.h = 0xffc0; 145 p5.l = 0x0014; 146 if cc jump 1f; 147 r7.l = W[p5]; 1481: 149#endif 150 r1 = sp; 151 SP += -12; 152 call _do_irq; 153 SP += 12; 154 call _return_from_int; 155.Lcommon_restore_context: 156 RESTORE_CONTEXT 157 rti; 158 159/* interrupt routine for ivhw - 5 */ 160ENTRY(_evt_ivhw) 161 SAVE_CONTEXT 162#ifdef CONFIG_FRAME_POINTER 163 fp = 0; 164#endif 165#ifdef ANOMALY_05000283 166 cc = r7 == r7; 167 p5.h = 0xffc0; 168 p5.l = 0x0014; 169 if cc jump 1f; 170 r7.l = W[p5]; 1711: 172#endif 173 p0.l = lo(TBUFCTL); 174 p0.h = hi(TBUFCTL); 175 r0 = 1; 176 [p0] = r0; 177 r0 = IRQ_HWERR; 178 r1 = sp; 179 180#ifdef CONFIG_HARDWARE_PM 181 r7 = SEQSTAT; 182 r7 = r7 >>> 0xe; 183 r6 = 0x1F; 184 r7 = r7 & r6; 185 r5 = 0x12; 186 cc = r7 == r5; 187 if cc jump .Lcall_do_ovf; /* deal with performance counter overflow */ 188#endif 189 190 SP += -12; 191 call _irq_panic; 192 SP += 12; 193 rti; 194#ifdef CONFIG_HARDWARE_PM 195.Lcall_do_ovf: 196 197 SP += -12; 198 call _pm_overflow; 199 SP += 12; 200 201 jump .Lcommon_restore_context; 202#endif 203 204/* interrupt routine for evt2 - 2. This is NMI. */ 205ENTRY(_evt_evt2) 206 SAVE_CONTEXT 207#ifdef CONFIG_FRAME_POINTER 208 fp = 0; 209#endif 210#ifdef ANOMALY_05000283 211 cc = r7 == r7; 212 p5.h = 0xffc0; 213 p5.l = 0x0014; 214 if cc jump 1f; 215 r7.l = W[p5]; 2161: 217#endif 218 r0 = IRQ_NMI; 219 r1 = sp; 220 SP += -12; 221 call _asm_do_IRQ; 222 SP += 12; 223 RESTORE_CONTEXT 224 rtn; 225 226/* interrupt routine for core timer - 6 */ 227ENTRY(_evt_timer) 228 TIMER_INTERRUPT_ENTRY(EVT_IVTMR_P) 229 230/* interrupt routine for evt7 - 7 */ 231ENTRY(_evt_evt7) 232 INTERRUPT_ENTRY(EVT_IVG7_P) 233ENTRY(_evt_evt8) 234 INTERRUPT_ENTRY(EVT_IVG8_P) 235ENTRY(_evt_evt9) 236 INTERRUPT_ENTRY(EVT_IVG9_P) 237ENTRY(_evt_evt10) 238 INTERRUPT_ENTRY(EVT_IVG10_P) 239ENTRY(_evt_evt11) 240 INTERRUPT_ENTRY(EVT_IVG11_P) 241ENTRY(_evt_evt12) 242 INTERRUPT_ENTRY(EVT_IVG12_P) 243ENTRY(_evt_evt13) 244 INTERRUPT_ENTRY(EVT_IVG13_P) 245 246 247 /* interrupt routine for system_call - 15 */ 248ENTRY(_evt_system_call) 249 SAVE_CONTEXT_SYSCALL 250#ifdef CONFIG_FRAME_POINTER 251 fp = 0; 252#endif 253 call _system_call; 254 jump .Lcommon_restore_context; 255ENDPROC(_evt_system_call) 256