162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 1995, 1996, 1997 Paul M. Antoine and Harald Koerfgen 462306a36Sopenharmony_ci * Copyright (C) 2000, 2001, 2002, 2003, 2005 Maciej W. Rozycki 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Written by Ralf Baechle and Andreas Busse, modified for DECstation 762306a36Sopenharmony_ci * support by Paul Antoine and Harald Koerfgen. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * completely rewritten: 1062306a36Sopenharmony_ci * Copyright (C) 1998 Harald Koerfgen 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Rewritten extensively for controller-driven IRQ support 1362306a36Sopenharmony_ci * by Maciej W. Rozycki. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <asm/addrspace.h> 1762306a36Sopenharmony_ci#include <asm/asm.h> 1862306a36Sopenharmony_ci#include <asm/mipsregs.h> 1962306a36Sopenharmony_ci#include <asm/regdef.h> 2062306a36Sopenharmony_ci#include <asm/stackframe.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <asm/dec/interrupts.h> 2362306a36Sopenharmony_ci#include <asm/dec/ioasic_addrs.h> 2462306a36Sopenharmony_ci#include <asm/dec/ioasic_ints.h> 2562306a36Sopenharmony_ci#include <asm/dec/kn01.h> 2662306a36Sopenharmony_ci#include <asm/dec/kn02.h> 2762306a36Sopenharmony_ci#include <asm/dec/kn02xa.h> 2862306a36Sopenharmony_ci#include <asm/dec/kn03.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define KN02_CSR_BASE CKSEG1ADDR(KN02_SLOT_BASE + KN02_CSR) 3162306a36Sopenharmony_ci#define KN02XA_IOASIC_BASE CKSEG1ADDR(KN02XA_SLOT_BASE + IOASIC_IOCTL) 3262306a36Sopenharmony_ci#define KN03_IOASIC_BASE CKSEG1ADDR(KN03_SLOT_BASE + IOASIC_IOCTL) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci .text 3562306a36Sopenharmony_ci .set noreorder 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * plat_irq_dispatch: Interrupt handler for DECstations 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * We follow the model in the Indy interrupt code by David Miller, where he 4062306a36Sopenharmony_ci * says: a lot of complication here is taken away because: 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * 1) We handle one interrupt and return, sitting in a loop 4362306a36Sopenharmony_ci * and moving across all the pending IRQ bits in the cause 4462306a36Sopenharmony_ci * register is _NOT_ the answer, the common case is one 4562306a36Sopenharmony_ci * pending IRQ so optimize in that direction. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * 2) We need not check against bits in the status register 4862306a36Sopenharmony_ci * IRQ mask, that would make this routine slow as hell. 4962306a36Sopenharmony_ci * 5062306a36Sopenharmony_ci * 3) Linux only thinks in terms of all IRQs on or all IRQs 5162306a36Sopenharmony_ci * off, nothing in between like BSD spl() brain-damage. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * Furthermore, the IRQs on the DECstations look basically (barring 5462306a36Sopenharmony_ci * software IRQs which we don't use at all) like... 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * DS2100/3100's, aka kn01, aka Pmax: 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * MIPS IRQ Source 5962306a36Sopenharmony_ci * -------- ------ 6062306a36Sopenharmony_ci * 0 Software (ignored) 6162306a36Sopenharmony_ci * 1 Software (ignored) 6262306a36Sopenharmony_ci * 2 SCSI 6362306a36Sopenharmony_ci * 3 Lance Ethernet 6462306a36Sopenharmony_ci * 4 DZ11 serial 6562306a36Sopenharmony_ci * 5 RTC 6662306a36Sopenharmony_ci * 6 Memory Controller & Video 6762306a36Sopenharmony_ci * 7 FPU 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * DS5000/200, aka kn02, aka 3max: 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * MIPS IRQ Source 7262306a36Sopenharmony_ci * -------- ------ 7362306a36Sopenharmony_ci * 0 Software (ignored) 7462306a36Sopenharmony_ci * 1 Software (ignored) 7562306a36Sopenharmony_ci * 2 TurboChannel 7662306a36Sopenharmony_ci * 3 RTC 7762306a36Sopenharmony_ci * 4 Reserved 7862306a36Sopenharmony_ci * 5 Memory Controller 7962306a36Sopenharmony_ci * 6 Reserved 8062306a36Sopenharmony_ci * 7 FPU 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * DS5000/1xx's, aka kn02ba, aka 3min: 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * MIPS IRQ Source 8562306a36Sopenharmony_ci * -------- ------ 8662306a36Sopenharmony_ci * 0 Software (ignored) 8762306a36Sopenharmony_ci * 1 Software (ignored) 8862306a36Sopenharmony_ci * 2 TurboChannel Slot 0 8962306a36Sopenharmony_ci * 3 TurboChannel Slot 1 9062306a36Sopenharmony_ci * 4 TurboChannel Slot 2 9162306a36Sopenharmony_ci * 5 TurboChannel Slot 3 (ASIC) 9262306a36Sopenharmony_ci * 6 Halt button 9362306a36Sopenharmony_ci * 7 FPU/R4k timer 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * DS5000/2x's, aka kn02ca, aka maxine: 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * MIPS IRQ Source 9862306a36Sopenharmony_ci * -------- ------ 9962306a36Sopenharmony_ci * 0 Software (ignored) 10062306a36Sopenharmony_ci * 1 Software (ignored) 10162306a36Sopenharmony_ci * 2 Periodic Interrupt (100usec) 10262306a36Sopenharmony_ci * 3 RTC 10362306a36Sopenharmony_ci * 4 I/O write timeout 10462306a36Sopenharmony_ci * 5 TurboChannel (ASIC) 10562306a36Sopenharmony_ci * 6 Halt Keycode from Access.Bus keyboard (CTRL-ALT-ENTER) 10662306a36Sopenharmony_ci * 7 FPU/R4k timer 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * DS5000/2xx's, aka kn03, aka 3maxplus: 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * MIPS IRQ Source 11162306a36Sopenharmony_ci * -------- ------ 11262306a36Sopenharmony_ci * 0 Software (ignored) 11362306a36Sopenharmony_ci * 1 Software (ignored) 11462306a36Sopenharmony_ci * 2 System Board (ASIC) 11562306a36Sopenharmony_ci * 3 RTC 11662306a36Sopenharmony_ci * 4 Reserved 11762306a36Sopenharmony_ci * 5 Memory 11862306a36Sopenharmony_ci * 6 Halt Button 11962306a36Sopenharmony_ci * 7 FPU/R4k timer 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * We handle the IRQ according to _our_ priority (see setup.c), 12262306a36Sopenharmony_ci * then we just return. If multiple IRQs are pending then we will 12362306a36Sopenharmony_ci * just take another exception, big deal. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci .align 5 12662306a36Sopenharmony_ci NESTED(plat_irq_dispatch, PT_SIZE, ra) 12762306a36Sopenharmony_ci .set noreorder 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * Get pending Interrupts 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci mfc0 t0,CP0_CAUSE # get pending interrupts 13362306a36Sopenharmony_ci mfc0 t1,CP0_STATUS 13462306a36Sopenharmony_ci#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) 13562306a36Sopenharmony_ci lw t2,cpu_fpu_mask 13662306a36Sopenharmony_ci#endif 13762306a36Sopenharmony_ci andi t0,ST0_IM # CAUSE.CE may be non-zero! 13862306a36Sopenharmony_ci and t0,t1 # isolate allowed ones 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci beqz t0,spurious 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) 14362306a36Sopenharmony_ci and t2,t0 14462306a36Sopenharmony_ci bnez t2,fpu # handle FPU immediately 14562306a36Sopenharmony_ci#endif 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * Find irq with highest priority 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci # open coded PTR_LA t1, cpu_mask_nr_tbl 15162306a36Sopenharmony_ci#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) 15262306a36Sopenharmony_ci # open coded la t1, cpu_mask_nr_tbl 15362306a36Sopenharmony_ci lui t1, %hi(cpu_mask_nr_tbl) 15462306a36Sopenharmony_ci addiu t1, %lo(cpu_mask_nr_tbl) 15562306a36Sopenharmony_ci#else 15662306a36Sopenharmony_ci#error GCC `-msym32' option required for 64-bit DECstation builds 15762306a36Sopenharmony_ci#endif 15862306a36Sopenharmony_ci1: lw t2,(t1) 15962306a36Sopenharmony_ci nop 16062306a36Sopenharmony_ci and t2,t0 16162306a36Sopenharmony_ci beqz t2,1b 16262306a36Sopenharmony_ci addu t1,2*PTRSIZE # delay slot 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * Do the low-level stuff 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci lw a0,(-PTRSIZE)(t1) 16862306a36Sopenharmony_ci nop 16962306a36Sopenharmony_ci bgez a0,handle_it # irq_nr >= 0? 17062306a36Sopenharmony_ci # irq_nr < 0: it is an address 17162306a36Sopenharmony_ci nop 17262306a36Sopenharmony_ci jr a0 17362306a36Sopenharmony_ci # a trick to save a branch: 17462306a36Sopenharmony_ci lui t2,(KN03_IOASIC_BASE>>16)&0xffff 17562306a36Sopenharmony_ci # upper part of IOASIC Address 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* 17862306a36Sopenharmony_ci * Handle "IRQ Controller" Interrupts 17962306a36Sopenharmony_ci * Masked Interrupts are still visible and have to be masked "by hand". 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci FEXPORT(kn02_io_int) # 3max 18262306a36Sopenharmony_ci lui t0,(KN02_CSR_BASE>>16)&0xffff 18362306a36Sopenharmony_ci # get interrupt status and mask 18462306a36Sopenharmony_ci lw t0,(t0) 18562306a36Sopenharmony_ci nop 18662306a36Sopenharmony_ci andi t1,t0,KN02_IRQ_ALL 18762306a36Sopenharmony_ci b 1f 18862306a36Sopenharmony_ci srl t0,16 # shift interrupt mask 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci FEXPORT(kn02xa_io_int) # 3min/maxine 19162306a36Sopenharmony_ci lui t2,(KN02XA_IOASIC_BASE>>16)&0xffff 19262306a36Sopenharmony_ci # upper part of IOASIC Address 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci FEXPORT(kn03_io_int) # 3max+ (t2 loaded earlier) 19562306a36Sopenharmony_ci lw t0,IO_REG_SIR(t2) # get status: IOASIC sir 19662306a36Sopenharmony_ci lw t1,IO_REG_SIMR(t2) # get mask: IOASIC simr 19762306a36Sopenharmony_ci nop 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci1: and t0,t1 # mask out allowed ones 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci beqz t0,spurious 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * Find irq with highest priority 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci # open coded PTR_LA t1,asic_mask_nr_tbl 20762306a36Sopenharmony_ci#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32) 20862306a36Sopenharmony_ci # open coded la t1, asic_mask_nr_tbl 20962306a36Sopenharmony_ci lui t1, %hi(asic_mask_nr_tbl) 21062306a36Sopenharmony_ci addiu t1, %lo(asic_mask_nr_tbl) 21162306a36Sopenharmony_ci#else 21262306a36Sopenharmony_ci#error GCC `-msym32' option required for 64-bit DECstation builds 21362306a36Sopenharmony_ci#endif 21462306a36Sopenharmony_ci2: lw t2,(t1) 21562306a36Sopenharmony_ci nop 21662306a36Sopenharmony_ci and t2,t0 21762306a36Sopenharmony_ci beq zero,t2,2b 21862306a36Sopenharmony_ci addu t1,2*PTRSIZE # delay slot 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * Do the low-level stuff 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci lw a0,%lo(-PTRSIZE)(t1) 22462306a36Sopenharmony_ci nop 22562306a36Sopenharmony_ci bgez a0,handle_it # irq_nr >= 0? 22662306a36Sopenharmony_ci # irq_nr < 0: it is an address 22762306a36Sopenharmony_ci nop 22862306a36Sopenharmony_ci jr a0 22962306a36Sopenharmony_ci nop # delay slot 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* 23262306a36Sopenharmony_ci * Dispatch low-priority interrupts. We reconsider all status 23362306a36Sopenharmony_ci * bits again, which looks like a lose, but it makes the code 23462306a36Sopenharmony_ci * simple and O(log n), so it gets compensated. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci FEXPORT(cpu_all_int) # HALT, timers, software junk 23762306a36Sopenharmony_ci li a0,DEC_CPU_IRQ_BASE 23862306a36Sopenharmony_ci srl t0,CAUSEB_IP 23962306a36Sopenharmony_ci li t1,CAUSEF_IP>>CAUSEB_IP # mask 24062306a36Sopenharmony_ci b 1f 24162306a36Sopenharmony_ci li t2,4 # nr of bits / 2 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci FEXPORT(kn02_all_int) # impossible ? 24462306a36Sopenharmony_ci li a0,KN02_IRQ_BASE 24562306a36Sopenharmony_ci li t1,KN02_IRQ_ALL # mask 24662306a36Sopenharmony_ci b 1f 24762306a36Sopenharmony_ci li t2,4 # nr of bits / 2 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci FEXPORT(asic_all_int) # various I/O ASIC junk 25062306a36Sopenharmony_ci li a0,IO_IRQ_BASE 25162306a36Sopenharmony_ci li t1,IO_IRQ_ALL # mask 25262306a36Sopenharmony_ci b 1f 25362306a36Sopenharmony_ci li t2,8 # nr of bits / 2 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci/* 25662306a36Sopenharmony_ci * Dispatch DMA interrupts -- O(log n). 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci FEXPORT(asic_dma_int) # I/O ASIC DMA events 25962306a36Sopenharmony_ci li a0,IO_IRQ_BASE+IO_INR_DMA 26062306a36Sopenharmony_ci srl t0,IO_INR_DMA 26162306a36Sopenharmony_ci li t1,IO_IRQ_DMA>>IO_INR_DMA # mask 26262306a36Sopenharmony_ci li t2,8 # nr of bits / 2 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci /* 26562306a36Sopenharmony_ci * Find irq with highest priority. 26662306a36Sopenharmony_ci * Highest irq number takes precedence. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ci1: srlv t3,t1,t2 26962306a36Sopenharmony_ci2: xor t1,t3 27062306a36Sopenharmony_ci and t3,t0,t1 27162306a36Sopenharmony_ci beqz t3,3f 27262306a36Sopenharmony_ci nop 27362306a36Sopenharmony_ci move t0,t3 27462306a36Sopenharmony_ci addu a0,t2 27562306a36Sopenharmony_ci3: srl t2,1 27662306a36Sopenharmony_ci bnez t2,2b 27762306a36Sopenharmony_ci srlv t3,t1,t2 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cihandle_it: 28062306a36Sopenharmony_ci j dec_irq_dispatch 28162306a36Sopenharmony_ci nop 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci#if defined(CONFIG_32BIT) && defined(CONFIG_MIPS_FP_SUPPORT) 28462306a36Sopenharmony_cifpu: 28562306a36Sopenharmony_ci lw t0,fpu_kstat_irq 28662306a36Sopenharmony_ci nop 28762306a36Sopenharmony_ci lw t1,(t0) 28862306a36Sopenharmony_ci nop 28962306a36Sopenharmony_ci addu t1,1 29062306a36Sopenharmony_ci j handle_fpe_int 29162306a36Sopenharmony_ci sw t1,(t0) 29262306a36Sopenharmony_ci#endif 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cispurious: 29562306a36Sopenharmony_ci j spurious_interrupt 29662306a36Sopenharmony_ci nop 29762306a36Sopenharmony_ci END(plat_irq_dispatch) 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* 30062306a36Sopenharmony_ci * Generic unimplemented interrupt routines -- cpu_mask_nr_tbl 30162306a36Sopenharmony_ci * and asic_mask_nr_tbl are initialized to point all interrupts here. 30262306a36Sopenharmony_ci * The tables are then filled in by machine-specific initialisation 30362306a36Sopenharmony_ci * in dec_setup(). 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci FEXPORT(dec_intr_unimplemented) 30662306a36Sopenharmony_ci move a1,t0 # cheats way of printing an arg! 30762306a36Sopenharmony_ci ASM_PANIC("Unimplemented cpu interrupt! CP0_CAUSE: 0x%08x"); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci FEXPORT(asic_intr_unimplemented) 31062306a36Sopenharmony_ci move a1,t0 # cheats way of printing an arg! 31162306a36Sopenharmony_ci ASM_PANIC("Unimplemented asic interrupt! ASIC ISR: 0x%08x"); 312