2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/module.h>
14 #include <linux/irq.h>
15 #include <asm/irq_cpu.h>
16 #include <asm/mipsregs.h>
17 #include <bcm63xx_cpu.h>
18 #include <bcm63xx_regs.h>
19 #include <bcm63xx_io.h>
20 #include <bcm63xx_irq.h>
23 * dispatch internal devices IRQ (uart, enet, watchdog, ...). do not
24 * prioritize any interrupt relatively to another. the static counter
25 * will resume the loop where it ended the last time we left this
28 static void bcm63xx_irq_dispatch_internal(void)
33 pending = bcm_perf_readl(PERF_IRQMASK_REG) &
34 bcm_perf_readl(PERF_IRQSTAT_REG);
43 if (pending & (1 << to_call)) {
44 do_IRQ(to_call + IRQ_INTERNAL_BASE);
50 asmlinkage void plat_irq_dispatch(void)
55 cause = read_c0_cause() & read_c0_status() & ST0_IM;
60 if (cause & CAUSEF_IP7)
62 if (cause & CAUSEF_IP2)
63 bcm63xx_irq_dispatch_internal();
64 if (cause & CAUSEF_IP3)
66 if (cause & CAUSEF_IP4)
68 if (cause & CAUSEF_IP5)
70 if (cause & CAUSEF_IP6)
76 * internal IRQs operations: only mask/unmask on PERF irq mask
79 static inline void bcm63xx_internal_irq_mask(unsigned int irq)
83 irq -= IRQ_INTERNAL_BASE;
84 mask = bcm_perf_readl(PERF_IRQMASK_REG);
86 bcm_perf_writel(mask, PERF_IRQMASK_REG);
89 static void bcm63xx_internal_irq_unmask(unsigned int irq)
93 irq -= IRQ_INTERNAL_BASE;
94 mask = bcm_perf_readl(PERF_IRQMASK_REG);
96 bcm_perf_writel(mask, PERF_IRQMASK_REG);
99 static unsigned int bcm63xx_internal_irq_startup(unsigned int irq)
101 bcm63xx_internal_irq_unmask(irq);
106 * external IRQs operations: mask/unmask and clear on PERF external
107 * irq control register.
109 static void bcm63xx_external_irq_mask(unsigned int irq)
114 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
115 reg &= ~EXTIRQ_CFG_MASK(irq);
116 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
119 static void bcm63xx_external_irq_unmask(unsigned int irq)
124 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
125 reg |= EXTIRQ_CFG_MASK(irq);
126 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
129 static void bcm63xx_external_irq_clear(unsigned int irq)
134 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
135 reg |= EXTIRQ_CFG_CLEAR(irq);
136 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
139 static unsigned int bcm63xx_external_irq_startup(unsigned int irq)
141 set_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
143 bcm63xx_external_irq_unmask(irq);
147 static void bcm63xx_external_irq_shutdown(unsigned int irq)
149 bcm63xx_external_irq_mask(irq);
150 clear_c0_status(0x100 << (irq - IRQ_MIPS_BASE));
151 irq_disable_hazard();
154 static int bcm63xx_external_irq_set_type(unsigned int irq,
155 unsigned int flow_type)
158 struct irq_desc *desc = irq_desc + irq;
162 flow_type &= IRQ_TYPE_SENSE_MASK;
164 if (flow_type == IRQ_TYPE_NONE)
165 flow_type = IRQ_TYPE_LEVEL_LOW;
167 reg = bcm_perf_readl(PERF_EXTIRQ_CFG_REG);
169 case IRQ_TYPE_EDGE_BOTH:
170 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
171 reg |= EXTIRQ_CFG_BOTHEDGE(irq);
174 case IRQ_TYPE_EDGE_RISING:
175 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
176 reg |= EXTIRQ_CFG_SENSE(irq);
177 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
180 case IRQ_TYPE_EDGE_FALLING:
181 reg &= ~EXTIRQ_CFG_LEVELSENSE(irq);
182 reg &= ~EXTIRQ_CFG_SENSE(irq);
183 reg &= ~EXTIRQ_CFG_BOTHEDGE(irq);
186 case IRQ_TYPE_LEVEL_HIGH:
187 reg |= EXTIRQ_CFG_LEVELSENSE(irq);
188 reg |= EXTIRQ_CFG_SENSE(irq);
191 case IRQ_TYPE_LEVEL_LOW:
192 reg |= EXTIRQ_CFG_LEVELSENSE(irq);
193 reg &= ~EXTIRQ_CFG_SENSE(irq);
197 printk(KERN_ERR "bogus flow type combination given !\n");
200 bcm_perf_writel(reg, PERF_EXTIRQ_CFG_REG);
202 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
203 desc->status |= IRQ_LEVEL;
204 desc->handle_irq = handle_level_irq;
206 desc->handle_irq = handle_edge_irq;
212 static struct irq_chip bcm63xx_internal_irq_chip = {
213 .name = "bcm63xx_ipic",
214 .startup = bcm63xx_internal_irq_startup,
215 .shutdown = bcm63xx_internal_irq_mask,
217 .mask = bcm63xx_internal_irq_mask,
218 .mask_ack = bcm63xx_internal_irq_mask,
219 .unmask = bcm63xx_internal_irq_unmask,
222 static struct irq_chip bcm63xx_external_irq_chip = {
223 .name = "bcm63xx_epic",
224 .startup = bcm63xx_external_irq_startup,
225 .shutdown = bcm63xx_external_irq_shutdown,
227 .ack = bcm63xx_external_irq_clear,
229 .mask = bcm63xx_external_irq_mask,
230 .unmask = bcm63xx_external_irq_unmask,
232 .set_type = bcm63xx_external_irq_set_type,
235 static struct irqaction cpu_ip2_cascade_action = {
236 .handler = no_action,
237 .name = "cascade_ip2",
240 void __init arch_init_irq(void)
245 for (i = IRQ_INTERNAL_BASE; i < NR_IRQS; ++i)
246 set_irq_chip_and_handler(i, &bcm63xx_internal_irq_chip,
249 for (i = IRQ_EXT_BASE; i < IRQ_EXT_BASE + 4; ++i)
250 set_irq_chip_and_handler(i, &bcm63xx_external_irq_chip,
253 setup_irq(IRQ_MIPS_BASE + 2, &cpu_ip2_cascade_action);