1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * This file is subject to the terms and conditions of the GNU General Public
3*4882a593Smuzhiyun * License. See the file "COPYING" in the main directory of this archive
4*4882a593Smuzhiyun * for more details.
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Carsten Langgaard, carstenl@mips.com
7*4882a593Smuzhiyun * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
8*4882a593Smuzhiyun * Copyright (C) 2001 Ralf Baechle
9*4882a593Smuzhiyun * Copyright (C) 2013 Imagination Technologies Ltd.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Routines for generic manipulation of the interrupts found on the MIPS
12*4882a593Smuzhiyun * Malta board. The interrupt controller is located in the South Bridge
13*4882a593Smuzhiyun * a PIIX4 device with two internal 82C95 interrupt controllers.
14*4882a593Smuzhiyun */
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/irq.h>
17*4882a593Smuzhiyun #include <linux/irqchip.h>
18*4882a593Smuzhiyun #include <linux/sched.h>
19*4882a593Smuzhiyun #include <linux/smp.h>
20*4882a593Smuzhiyun #include <linux/interrupt.h>
21*4882a593Smuzhiyun #include <linux/io.h>
22*4882a593Smuzhiyun #include <linux/of_irq.h>
23*4882a593Smuzhiyun #include <linux/kernel_stat.h>
24*4882a593Smuzhiyun #include <linux/kernel.h>
25*4882a593Smuzhiyun #include <linux/random.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include <asm/traps.h>
28*4882a593Smuzhiyun #include <asm/i8259.h>
29*4882a593Smuzhiyun #include <asm/irq_cpu.h>
30*4882a593Smuzhiyun #include <asm/irq_regs.h>
31*4882a593Smuzhiyun #include <asm/mips-boards/malta.h>
32*4882a593Smuzhiyun #include <asm/mips-boards/maltaint.h>
33*4882a593Smuzhiyun #include <asm/mips-cps.h>
34*4882a593Smuzhiyun #include <asm/gt64120.h>
35*4882a593Smuzhiyun #include <asm/mips-boards/generic.h>
36*4882a593Smuzhiyun #include <asm/mips-boards/msc01_pci.h>
37*4882a593Smuzhiyun #include <asm/msc01_ic.h>
38*4882a593Smuzhiyun #include <asm/setup.h>
39*4882a593Smuzhiyun #include <asm/rtlx.h>
40*4882a593Smuzhiyun
mips_pcibios_iack(void)41*4882a593Smuzhiyun static inline int mips_pcibios_iack(void)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun int irq;
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /*
46*4882a593Smuzhiyun * Determine highest priority pending interrupt by performing
47*4882a593Smuzhiyun * a PCI Interrupt Acknowledge cycle.
48*4882a593Smuzhiyun */
49*4882a593Smuzhiyun switch (mips_revision_sconid) {
50*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCIT:
51*4882a593Smuzhiyun case MIPS_REVISION_SCON_ROCIT:
52*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCITSC:
53*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCITSCP:
54*4882a593Smuzhiyun MSC_READ(MSC01_PCI_IACK, irq);
55*4882a593Smuzhiyun irq &= 0xff;
56*4882a593Smuzhiyun break;
57*4882a593Smuzhiyun case MIPS_REVISION_SCON_GT64120:
58*4882a593Smuzhiyun irq = GT_READ(GT_PCI0_IACK_OFS);
59*4882a593Smuzhiyun irq &= 0xff;
60*4882a593Smuzhiyun break;
61*4882a593Smuzhiyun case MIPS_REVISION_SCON_BONITO:
62*4882a593Smuzhiyun /* The following will generate a PCI IACK cycle on the
63*4882a593Smuzhiyun * Bonito controller. It's a little bit kludgy, but it
64*4882a593Smuzhiyun * was the easiest way to implement it in hardware at
65*4882a593Smuzhiyun * the given time.
66*4882a593Smuzhiyun */
67*4882a593Smuzhiyun BONITO_PCIMAP_CFG = 0x20000;
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun /* Flush Bonito register block */
70*4882a593Smuzhiyun (void) BONITO_PCIMAP_CFG;
71*4882a593Smuzhiyun iob(); /* sync */
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun irq = __raw_readl((u32 *)_pcictrl_bonito_pcicfg);
74*4882a593Smuzhiyun iob(); /* sync */
75*4882a593Smuzhiyun irq &= 0xff;
76*4882a593Smuzhiyun BONITO_PCIMAP_CFG = 0;
77*4882a593Smuzhiyun break;
78*4882a593Smuzhiyun default:
79*4882a593Smuzhiyun pr_emerg("Unknown system controller.\n");
80*4882a593Smuzhiyun return -1;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun return irq;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
corehi_irqdispatch(void)85*4882a593Smuzhiyun static void corehi_irqdispatch(void)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun unsigned int intedge, intsteer, pcicmd, pcibadaddr;
88*4882a593Smuzhiyun unsigned int pcimstat, intisr, inten, intpol;
89*4882a593Smuzhiyun unsigned int intrcause, datalo, datahi;
90*4882a593Smuzhiyun struct pt_regs *regs = get_irq_regs();
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n");
93*4882a593Smuzhiyun pr_emerg("epc : %08lx\nStatus: %08lx\n"
94*4882a593Smuzhiyun "Cause : %08lx\nbadVaddr : %08lx\n",
95*4882a593Smuzhiyun regs->cp0_epc, regs->cp0_status,
96*4882a593Smuzhiyun regs->cp0_cause, regs->cp0_badvaddr);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun /* Read all the registers and then print them as there is a
99*4882a593Smuzhiyun problem with interspersed printk's upsetting the Bonito controller.
100*4882a593Smuzhiyun Do it for the others too.
101*4882a593Smuzhiyun */
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun switch (mips_revision_sconid) {
104*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCIT:
105*4882a593Smuzhiyun case MIPS_REVISION_SCON_ROCIT:
106*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCITSC:
107*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCITSCP:
108*4882a593Smuzhiyun ll_msc_irq();
109*4882a593Smuzhiyun break;
110*4882a593Smuzhiyun case MIPS_REVISION_SCON_GT64120:
111*4882a593Smuzhiyun intrcause = GT_READ(GT_INTRCAUSE_OFS);
112*4882a593Smuzhiyun datalo = GT_READ(GT_CPUERR_ADDRLO_OFS);
113*4882a593Smuzhiyun datahi = GT_READ(GT_CPUERR_ADDRHI_OFS);
114*4882a593Smuzhiyun pr_emerg("GT_INTRCAUSE = %08x\n", intrcause);
115*4882a593Smuzhiyun pr_emerg("GT_CPUERR_ADDR = %02x%08x\n",
116*4882a593Smuzhiyun datahi, datalo);
117*4882a593Smuzhiyun break;
118*4882a593Smuzhiyun case MIPS_REVISION_SCON_BONITO:
119*4882a593Smuzhiyun pcibadaddr = BONITO_PCIBADADDR;
120*4882a593Smuzhiyun pcimstat = BONITO_PCIMSTAT;
121*4882a593Smuzhiyun intisr = BONITO_INTISR;
122*4882a593Smuzhiyun inten = BONITO_INTEN;
123*4882a593Smuzhiyun intpol = BONITO_INTPOL;
124*4882a593Smuzhiyun intedge = BONITO_INTEDGE;
125*4882a593Smuzhiyun intsteer = BONITO_INTSTEER;
126*4882a593Smuzhiyun pcicmd = BONITO_PCICMD;
127*4882a593Smuzhiyun pr_emerg("BONITO_INTISR = %08x\n", intisr);
128*4882a593Smuzhiyun pr_emerg("BONITO_INTEN = %08x\n", inten);
129*4882a593Smuzhiyun pr_emerg("BONITO_INTPOL = %08x\n", intpol);
130*4882a593Smuzhiyun pr_emerg("BONITO_INTEDGE = %08x\n", intedge);
131*4882a593Smuzhiyun pr_emerg("BONITO_INTSTEER = %08x\n", intsteer);
132*4882a593Smuzhiyun pr_emerg("BONITO_PCICMD = %08x\n", pcicmd);
133*4882a593Smuzhiyun pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr);
134*4882a593Smuzhiyun pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat);
135*4882a593Smuzhiyun break;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun die("CoreHi interrupt", regs);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
corehi_handler(int irq,void * dev_id)141*4882a593Smuzhiyun static irqreturn_t corehi_handler(int irq, void *dev_id)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun corehi_irqdispatch();
144*4882a593Smuzhiyun return IRQ_HANDLED;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun static msc_irqmap_t msc_irqmap[] __initdata = {
148*4882a593Smuzhiyun {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0},
149*4882a593Smuzhiyun {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0},
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap);
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun static msc_irqmap_t msc_eicirqmap[] __initdata = {
154*4882a593Smuzhiyun {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
155*4882a593Smuzhiyun {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0},
156*4882a593Smuzhiyun {MSC01E_INT_I8259A, MSC01_IRQ_LEVEL, 0},
157*4882a593Smuzhiyun {MSC01E_INT_SMI, MSC01_IRQ_LEVEL, 0},
158*4882a593Smuzhiyun {MSC01E_INT_COREHI, MSC01_IRQ_LEVEL, 0},
159*4882a593Smuzhiyun {MSC01E_INT_CORELO, MSC01_IRQ_LEVEL, 0},
160*4882a593Smuzhiyun {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0},
161*4882a593Smuzhiyun {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0},
162*4882a593Smuzhiyun {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
163*4882a593Smuzhiyun {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap);
167*4882a593Smuzhiyun
arch_init_irq(void)168*4882a593Smuzhiyun void __init arch_init_irq(void)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun int corehi_irq;
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /*
173*4882a593Smuzhiyun * Preallocate the i8259's expected virq's here. Since irqchip_init()
174*4882a593Smuzhiyun * will probe the irqchips in hierarchial order, i8259 is probed last.
175*4882a593Smuzhiyun * If anything allocates a virq before the i8259 is probed, it will
176*4882a593Smuzhiyun * be given one of the i8259's expected range and consequently setup
177*4882a593Smuzhiyun * of the i8259 will fail.
178*4882a593Smuzhiyun */
179*4882a593Smuzhiyun WARN(irq_alloc_descs(I8259A_IRQ_BASE, I8259A_IRQ_BASE,
180*4882a593Smuzhiyun 16, numa_node_id()) < 0,
181*4882a593Smuzhiyun "Cannot reserve i8259 virqs at IRQ%d\n", I8259A_IRQ_BASE);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun i8259_set_poll(mips_pcibios_iack);
184*4882a593Smuzhiyun irqchip_init();
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun switch (mips_revision_sconid) {
187*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCIT:
188*4882a593Smuzhiyun case MIPS_REVISION_SCON_ROCIT:
189*4882a593Smuzhiyun if (cpu_has_veic)
190*4882a593Smuzhiyun init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
191*4882a593Smuzhiyun MSC01E_INT_BASE, msc_eicirqmap,
192*4882a593Smuzhiyun msc_nr_eicirqs);
193*4882a593Smuzhiyun else
194*4882a593Smuzhiyun init_msc_irqs(MIPS_MSC01_IC_REG_BASE,
195*4882a593Smuzhiyun MSC01C_INT_BASE, msc_irqmap,
196*4882a593Smuzhiyun msc_nr_irqs);
197*4882a593Smuzhiyun break;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCITSC:
200*4882a593Smuzhiyun case MIPS_REVISION_SCON_SOCITSCP:
201*4882a593Smuzhiyun if (cpu_has_veic)
202*4882a593Smuzhiyun init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
203*4882a593Smuzhiyun MSC01E_INT_BASE, msc_eicirqmap,
204*4882a593Smuzhiyun msc_nr_eicirqs);
205*4882a593Smuzhiyun else
206*4882a593Smuzhiyun init_msc_irqs(MIPS_SOCITSC_IC_REG_BASE,
207*4882a593Smuzhiyun MSC01C_INT_BASE, msc_irqmap,
208*4882a593Smuzhiyun msc_nr_irqs);
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (mips_gic_present()) {
212*4882a593Smuzhiyun corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
213*4882a593Smuzhiyun } else if (cpu_has_veic) {
214*4882a593Smuzhiyun set_vi_handler(MSC01E_INT_COREHI, corehi_irqdispatch);
215*4882a593Smuzhiyun corehi_irq = MSC01E_INT_BASE + MSC01E_INT_COREHI;
216*4882a593Smuzhiyun } else {
217*4882a593Smuzhiyun corehi_irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_COREHI;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun if (request_irq(corehi_irq, corehi_handler, IRQF_NO_THREAD, "CoreHi",
221*4882a593Smuzhiyun NULL))
222*4882a593Smuzhiyun pr_err("Failed to request irq %d (CoreHi)\n", corehi_irq);
223*4882a593Smuzhiyun }
224