xref: /openbmc/linux/arch/arm/mach-dove/irq.c (revision b8cd337c)
1 /*
2  * arch/arm/mach-dove/irq.c
3  *
4  * Dove IRQ handling.
5  *
6  * This file is licensed under the terms of the GNU General Public
7  * License version 2.  This program is licensed "as is" without any
8  * warranty of any kind, whether express or implied.
9  */
10 
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/irq.h>
14 #include <linux/gpio.h>
15 #include <linux/io.h>
16 #include <asm/exception.h>
17 #include <asm/mach/arch.h>
18 #include <plat/irq.h>
19 #include <asm/mach/irq.h>
20 #include <mach/pm.h>
21 #include <mach/bridge-regs.h>
22 #include <plat/orion-gpio.h>
23 #include "common.h"
24 
25 static void pmu_irq_mask(struct irq_data *d)
26 {
27 	int pin = irq_to_pmu(d->irq);
28 	u32 u;
29 
30 	u = readl(PMU_INTERRUPT_MASK);
31 	u &= ~(1 << (pin & 31));
32 	writel(u, PMU_INTERRUPT_MASK);
33 }
34 
35 static void pmu_irq_unmask(struct irq_data *d)
36 {
37 	int pin = irq_to_pmu(d->irq);
38 	u32 u;
39 
40 	u = readl(PMU_INTERRUPT_MASK);
41 	u |= 1 << (pin & 31);
42 	writel(u, PMU_INTERRUPT_MASK);
43 }
44 
45 static void pmu_irq_ack(struct irq_data *d)
46 {
47 	int pin = irq_to_pmu(d->irq);
48 	u32 u;
49 
50 	/*
51 	 * The PMU mask register is not RW0C: it is RW.  This means that
52 	 * the bits take whatever value is written to them; if you write
53 	 * a '1', you will set the interrupt.
54 	 *
55 	 * Unfortunately this means there is NO race free way to clear
56 	 * these interrupts.
57 	 *
58 	 * So, let's structure the code so that the window is as small as
59 	 * possible.
60 	 */
61 	u = ~(1 << (pin & 31));
62 	u &= readl_relaxed(PMU_INTERRUPT_CAUSE);
63 	writel_relaxed(u, PMU_INTERRUPT_CAUSE);
64 }
65 
66 static struct irq_chip pmu_irq_chip = {
67 	.name		= "pmu_irq",
68 	.irq_mask	= pmu_irq_mask,
69 	.irq_unmask	= pmu_irq_unmask,
70 	.irq_ack	= pmu_irq_ack,
71 };
72 
73 static void pmu_irq_handler(struct irq_desc *desc)
74 {
75 	unsigned long cause = readl(PMU_INTERRUPT_CAUSE);
76 	unsigned int irq;
77 
78 	cause &= readl(PMU_INTERRUPT_MASK);
79 	if (cause == 0) {
80 		do_bad_IRQ(desc);
81 		return;
82 	}
83 
84 	for (irq = 0; irq < NR_PMU_IRQS; irq++) {
85 		if (!(cause & (1 << irq)))
86 			continue;
87 		irq = pmu_to_irq(irq);
88 		generic_handle_irq(irq);
89 	}
90 }
91 
92 static int __initdata gpio0_irqs[4] = {
93 	IRQ_DOVE_GPIO_0_7,
94 	IRQ_DOVE_GPIO_8_15,
95 	IRQ_DOVE_GPIO_16_23,
96 	IRQ_DOVE_GPIO_24_31,
97 };
98 
99 static int __initdata gpio1_irqs[4] = {
100 	IRQ_DOVE_HIGH_GPIO,
101 	0,
102 	0,
103 	0,
104 };
105 
106 static int __initdata gpio2_irqs[4] = {
107 	0,
108 	0,
109 	0,
110 	0,
111 };
112 
113 static void __iomem *dove_irq_base = IRQ_VIRT_BASE;
114 
115 static asmlinkage void
116 __exception_irq_entry dove_legacy_handle_irq(struct pt_regs *regs)
117 {
118 	u32 stat;
119 
120 	stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_LOW_OFF);
121 	stat &= readl_relaxed(dove_irq_base + IRQ_MASK_LOW_OFF);
122 	if (stat) {
123 		unsigned int hwirq = 1 + __fls(stat);
124 		handle_IRQ(hwirq, regs);
125 		return;
126 	}
127 	stat = readl_relaxed(dove_irq_base + IRQ_CAUSE_HIGH_OFF);
128 	stat &= readl_relaxed(dove_irq_base + IRQ_MASK_HIGH_OFF);
129 	if (stat) {
130 		unsigned int hwirq = 33 + __fls(stat);
131 		handle_IRQ(hwirq, regs);
132 		return;
133 	}
134 }
135 
136 void __init dove_init_irq(void)
137 {
138 	int i;
139 
140 	orion_irq_init(1, IRQ_VIRT_BASE + IRQ_MASK_LOW_OFF);
141 	orion_irq_init(33, IRQ_VIRT_BASE + IRQ_MASK_HIGH_OFF);
142 
143 	set_handle_irq(dove_legacy_handle_irq);
144 
145 	/*
146 	 * Initialize gpiolib for GPIOs 0-71.
147 	 */
148 	orion_gpio_init(NULL, 0, 32, DOVE_GPIO_LO_VIRT_BASE, 0,
149 			IRQ_DOVE_GPIO_START, gpio0_irqs);
150 
151 	orion_gpio_init(NULL, 32, 32, DOVE_GPIO_HI_VIRT_BASE, 0,
152 			IRQ_DOVE_GPIO_START + 32, gpio1_irqs);
153 
154 	orion_gpio_init(NULL, 64, 8, DOVE_GPIO2_VIRT_BASE, 0,
155 			IRQ_DOVE_GPIO_START + 64, gpio2_irqs);
156 
157 	/*
158 	 * Mask and clear PMU interrupts
159 	 */
160 	writel(0, PMU_INTERRUPT_MASK);
161 	writel(0, PMU_INTERRUPT_CAUSE);
162 
163 	for (i = IRQ_DOVE_PMU_START; i < NR_IRQS; i++) {
164 		irq_set_chip_and_handler(i, &pmu_irq_chip, handle_level_irq);
165 		irq_set_status_flags(i, IRQ_LEVEL);
166 		irq_clear_status_flags(i, IRQ_NOREQUEST);
167 	}
168 	irq_set_chained_handler(IRQ_DOVE_PMU, pmu_irq_handler);
169 }
170