1/* 2 * Copyright (C) 2003 PMC-Sierra Inc. 3 * Author: Manish Lachwani (lachwani@pmc-sierra.com) 4 * 5 * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or (at your 10 * option) any later version. 11 * 12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 15 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 16 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 17 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 18 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 21 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 * 23 * You should have received a copy of the GNU General Public License along 24 * with this program; if not, write to the Free Software Foundation, Inc., 25 * 675 Mass Ave, Cambridge, MA 02139, USA. 26 * 27 * Second level Interrupt handlers for the PMC-Sierra Titan/Yosemite board 28 */ 29#include <linux/errno.h> 30#include <linux/init.h> 31#include <linux/kernel_stat.h> 32#include <linux/module.h> 33#include <linux/signal.h> 34#include <linux/sched.h> 35#include <linux/types.h> 36#include <linux/interrupt.h> 37#include <linux/ioport.h> 38#include <linux/irq.h> 39#include <linux/timex.h> 40#include <linux/random.h> 41#include <linux/bitops.h> 42#include <asm/bootinfo.h> 43#include <asm/io.h> 44#include <asm/irq.h> 45#include <asm/irq_cpu.h> 46#include <asm/mipsregs.h> 47#include <asm/system.h> 48#include <asm/titan_dep.h> 49 50/* Hypertransport specific */ 51#define IRQ_ACK_BITS 0x00000000 /* Ack bits */ 52 53#define HYPERTRANSPORT_INTA 0x78 /* INTA# */ 54#define HYPERTRANSPORT_INTB 0x79 /* INTB# */ 55#define HYPERTRANSPORT_INTC 0x7a /* INTC# */ 56#define HYPERTRANSPORT_INTD 0x7b /* INTD# */ 57 58extern void titan_mailbox_irq(void); 59 60#ifdef CONFIG_HYPERTRANSPORT 61/* 62 * Handle hypertransport & SMP interrupts. The interrupt lines are scarce. 63 * For interprocessor interrupts, the best thing to do is to use the INTMSG 64 * register. We use the same external interrupt line, i.e. INTB3 and monitor 65 * another status bit 66 */ 67static void ll_ht_smp_irq_handler(int irq) 68{ 69 u32 status = OCD_READ(RM9000x2_OCD_INTP0STATUS4); 70 71 /* Ack all the bits that correspond to the interrupt sources */ 72 if (status != 0) 73 OCD_WRITE(RM9000x2_OCD_INTP0STATUS4, IRQ_ACK_BITS); 74 75 status = OCD_READ(RM9000x2_OCD_INTP1STATUS4); 76 if (status != 0) 77 OCD_WRITE(RM9000x2_OCD_INTP1STATUS4, IRQ_ACK_BITS); 78 79#ifdef CONFIG_HT_LEVEL_TRIGGER 80 /* 81 * Level Trigger Mode only. Send the HT EOI message back to the source. 82 */ 83 switch (status) { 84 case 0x1000000: 85 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTA); 86 break; 87 case 0x2000000: 88 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTB); 89 break; 90 case 0x4000000: 91 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTC); 92 break; 93 case 0x8000000: 94 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTD); 95 break; 96 case 0x0000001: 97 /* PLX */ 98 OCD_WRITE(RM9000x2_OCD_HTEOI, 0x20); 99 OCD_WRITE(IRQ_CLEAR_REG, IRQ_ACK_BITS); 100 break; 101 case 0xf000000: 102 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTA); 103 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTB); 104 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTC); 105 OCD_WRITE(RM9000x2_OCD_HTEOI, HYPERTRANSPORT_INTD); 106 break; 107 } 108#endif /* CONFIG_HT_LEVEL_TRIGGER */ 109 110 do_IRQ(irq); 111} 112#endif 113 114asmlinkage void plat_irq_dispatch(void) 115{ 116 unsigned int cause = read_c0_cause(); 117 unsigned int status = read_c0_status(); 118 unsigned int pending = cause & status; 119 120 if (pending & STATUSF_IP7) { 121 do_IRQ(7); 122 } else if (pending & STATUSF_IP2) { 123#ifdef CONFIG_HYPERTRANSPORT 124 ll_ht_smp_irq_handler(2); 125#else 126 do_IRQ(2); 127#endif 128 } else if (pending & STATUSF_IP3) { 129 do_IRQ(3); 130 } else if (pending & STATUSF_IP4) { 131 do_IRQ(4); 132 } else if (pending & STATUSF_IP5) { 133#ifdef CONFIG_SMP 134 titan_mailbox_irq(); 135#else 136 do_IRQ(5); 137#endif 138 } else if (pending & STATUSF_IP6) { 139 do_IRQ(4); 140 } 141} 142 143/* 144 * Initialize the next level interrupt handler 145 */ 146void __init arch_init_irq(void) 147{ 148 clear_c0_status(ST0_IM); 149 150 mips_cpu_irq_init(); 151 rm7k_cpu_irq_init(); 152 rm9k_cpu_irq_init(); 153} 154