1/*
2 * Carsten Langgaard, carstenl@mips.com
3 * Copyright (C) 2000, 2001 MIPS Technologies, Inc.
4 * Copyright (C) 2001 Ralf Baechle
5 *
6 *  This program is free software; you can distribute it and/or modify it
7 *  under the terms of the GNU General Public License (Version 2) as
8 *  published by the Free Software Foundation.
9 *
10 *  This program is distributed in the hope it will be useful, but WITHOUT
11 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 *  for more details.
14 *
15 *  You should have received a copy of the GNU General Public License along
16 *  with this program; if not, write to the Free Software Foundation, Inc.,
17 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
18 *
19 * Routines for generic manipulation of the interrupts found on the MIPS
20 * Malta board.
21 * The interrupt controller is located in the South Bridge a PIIX4 device
22 * with two internal 82C95 interrupt controllers.
23 */
24#include <linux/config.h>
25#include <linux/init.h>
26#include <linux/sched.h>
27#include <linux/slab.h>
28#include <linux/interrupt.h>
29#include <linux/kernel_stat.h>
30#include <linux/random.h>
31
32#include <asm/irq.h>
33#include <asm/io.h>
34#include <asm/mips-boards/malta.h>
35#include <asm/mips-boards/maltaint.h>
36#include <asm/mips-boards/piix4.h>
37#include <asm/gt64120.h>
38#include <asm/mips-boards/generic.h>
39#include <asm/mips-boards/msc01_pci.h>
40
41extern asmlinkage void mipsIRQ(void);
42extern asmlinkage void do_IRQ(int irq, struct pt_regs *regs);
43extern void init_i8259_irqs (void);
44extern int mips_pcibios_iack(void);
45
46static spinlock_t mips_irq_lock = SPIN_LOCK_UNLOCKED;
47
48static inline int get_int(int *irq)
49{
50	unsigned long flags;
51
52	spin_lock_irqsave(&mips_irq_lock, flags);
53
54	*irq = mips_pcibios_iack();
55
56	/*
57	 * IRQ7 is used to detect spurious interrupts.
58	 * The interrupt acknowledge cycle returns IRQ7, if no
59	 * interrupts is requested.
60	 * We can differentiate between this situation and a
61	 * "Normal" IRQ7 by reading the ISR.
62	 */
63	if (*irq == 7)
64	{
65		outb(PIIX4_OCW3_SEL | PIIX4_OCW3_ISR,
66		     PIIX4_ICTLR1_OCW3);
67		if (!(inb(PIIX4_ICTLR1_OCW3) & (1 << 7))) {
68			spin_unlock_irqrestore(&mips_irq_lock, flags);
69			printk("We got a spurious interrupt from PIIX4.\n");
70			atomic_inc(&irq_err_count);
71			return -1;    /* Spurious interrupt. */
72		}
73	}
74
75	spin_unlock_irqrestore(&mips_irq_lock, flags);
76
77	return 0;
78}
79
80void malta_hw0_irqdispatch(struct pt_regs *regs)
81{
82	int irq;
83
84	if (get_int(&irq))
85	        return;  /* interrupt has already been cleared */
86
87	do_IRQ(irq, regs);
88}
89
90void corehi_irqdispatch(struct pt_regs *regs)
91{
92        unsigned int data,datahi;
93
94	/* Mask out corehi interrupt. */
95	clear_c0_status(IE_IRQ3);
96
97        printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n");
98        printk("epc   : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n"
99, regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr);
100        switch(mips_revision_corid) {
101        case MIPS_REVISION_CORID_CORE_MSC:
102                break;
103        case MIPS_REVISION_CORID_QED_RM5261:
104        case MIPS_REVISION_CORID_CORE_LV:
105        case MIPS_REVISION_CORID_CORE_FPGA:
106                GT_READ(GT_INTRCAUSE_OFS, data);
107                printk("GT_INTRCAUSE = %08x\n", data);
108                GT_READ(0x70, data);
109                GT_READ(0x78, datahi);
110                printk("GT_CPU_ERR_ADDR = %0x2%08x\n", datahi,data);
111                break;
112        case MIPS_REVISION_CORID_BONITO64:
113        case MIPS_REVISION_CORID_CORE_20K:
114                data = BONITO_INTISR;
115                printk("BONITO_INTISR = %08x\n", data);
116                data = BONITO_INTEN;
117                printk("BONITO_INTEN = %08x\n", data);
118                data = BONITO_INTPOL;
119                printk("BONITO_INTPOL = %08x\n", data);
120                data = BONITO_INTEDGE;
121                printk("BONITO_INTEDGE = %08x\n", data);
122                data = BONITO_INTSTEER;
123                printk("BONITO_INTSTEER = %08x\n", data);
124                data = BONITO_PCICMD;
125                printk("BONITO_PCICMD = %08x\n", data);
126                break;
127        }
128
129        /* We die here*/
130        die("CoreHi interrupt", regs);
131}
132
133void __init init_IRQ(void)
134{
135	set_except_vector(0, mipsIRQ);
136	init_generic_irq();
137	init_i8259_irqs();
138
139#ifdef CONFIG_REMOTE_DEBUG
140	if (remote_debug) {
141		set_debug_traps();
142		breakpoint();
143	}
144#endif
145}
146
147
148