aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiko Stuebner <heiko@sntech.de>2013-01-29 13:25:22 -0500
committerKukjin Kim <kgene.kim@samsung.com>2013-01-29 13:25:22 -0500
commit1f629b7a3ced8e73784a9ae3b0d9039496878f18 (patch)
treea8298aa022b5e74905c50daa1c3fbafd3f980dd0
parentacf2d41d8595829eb0ac7bf6891f4875a78d4d6e (diff)
ARM: S3C24XX: transform irq handling into a declarative form
The irqs available on the machine and even the bit settings in the irq registers differ a lot through all the s3c24xx subarchitectures. This results in each subarch having its own irq init which adds its specific irqs to the base ones created in plat-s3c24xx/irq.c. This of course makes a future move to devicetree hard to implement. Therefore this patch transforms the base irq handling to a declarative style, where the irq types as well as its parent/child relationship gets read from a predefined datastructure, which later on can hopefully be easily represented in devicetree too. It should also be easy to include the subarch specific irqs here in later patches, reducing code size and duplication. It should not affect anything outside of the file, as the original irq numbers and their handling are preserved (hopefully) correctly. Signed-off-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r--arch/arm/plat-s3c24xx/Kconfig1
-rw-r--r--arch/arm/plat-s3c24xx/irq.c930
2 files changed, 445 insertions, 486 deletions
diff --git a/arch/arm/plat-s3c24xx/Kconfig b/arch/arm/plat-s3c24xx/Kconfig
index eef3b6a2f8a8..3bb5c8fd34a1 100644
--- a/arch/arm/plat-s3c24xx/Kconfig
+++ b/arch/arm/plat-s3c24xx/Kconfig
@@ -9,6 +9,7 @@ config PLAT_S3C24XX
9 select ARCH_REQUIRE_GPIOLIB 9 select ARCH_REQUIRE_GPIOLIB
10 select NO_IOPORT 10 select NO_IOPORT
11 select S3C_DEV_NAND 11 select S3C_DEV_NAND
12 select IRQ_DOMAIN
12 help 13 help
13 Base platform code for any Samsung S3C24XX device 14 Base platform code for any Samsung S3C24XX device
14 15
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index fe57bbbf166b..cdf1e92646c1 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -1,7 +1,9 @@
1/* linux/arch/arm/plat-s3c24xx/irq.c 1/*
2 * S3C24XX IRQ handling
2 * 3 *
3 * Copyright (c) 2003-2004 Simtec Electronics 4 * Copyright (c) 2003-2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 5 * Ben Dooks <ben@simtec.co.uk>
6 * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de>
5 * 7 *
6 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -12,175 +14,124 @@
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details. 16 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/ 17*/
20 18
21#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/slab.h>
22#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/io.h>
23#include <linux/err.h>
23#include <linux/interrupt.h> 24#include <linux/interrupt.h>
24#include <linux/ioport.h> 25#include <linux/ioport.h>
25#include <linux/device.h> 26#include <linux/device.h>
26#include <linux/syscore_ops.h> 27#include <linux/syscore_ops.h>
28#include <linux/irqdomain.h>
27 29
28#include <asm/irq.h>
29#include <asm/mach/irq.h> 30#include <asm/mach/irq.h>
30 31
31#include <plat/regs-irqtype.h> 32#include <mach/regs-irq.h>
33#include <mach/regs-gpio.h>
32 34
33#include <plat/cpu.h> 35#include <plat/cpu.h>
36#include <plat/regs-irqtype.h>
34#include <plat/pm.h> 37#include <plat/pm.h>
35#include <plat/irq.h> 38#include <plat/irq.h>
36 39
37static void 40#define S3C_IRQTYPE_NONE 0
38s3c_irq_mask(struct irq_data *data) 41#define S3C_IRQTYPE_EINT 1
39{ 42#define S3C_IRQTYPE_EDGE 2
40 unsigned int irqno = data->irq - IRQ_EINT0; 43#define S3C_IRQTYPE_LEVEL 3
41 unsigned long mask;
42
43 mask = __raw_readl(S3C2410_INTMSK);
44 mask |= 1UL << irqno;
45 __raw_writel(mask, S3C2410_INTMSK);
46}
47
48static inline void
49s3c_irq_ack(struct irq_data *data)
50{
51 unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
52
53 __raw_writel(bitval, S3C2410_SRCPND);
54 __raw_writel(bitval, S3C2410_INTPND);
55}
56
57static inline void
58s3c_irq_maskack(struct irq_data *data)
59{
60 unsigned long bitval = 1UL << (data->irq - IRQ_EINT0);
61 unsigned long mask;
62 44
63 mask = __raw_readl(S3C2410_INTMSK); 45struct s3c_irq_data {
64 __raw_writel(mask|bitval, S3C2410_INTMSK); 46 unsigned int type;
47 unsigned long parent_irq;
65 48
66 __raw_writel(bitval, S3C2410_SRCPND); 49 /* data gets filled during init */
67 __raw_writel(bitval, S3C2410_INTPND); 50 struct s3c_irq_intc *intc;
68} 51 unsigned long sub_bits;
69 52 struct s3c_irq_intc *sub_intc;
70
71static void
72s3c_irq_unmask(struct irq_data *data)
73{
74 unsigned int irqno = data->irq;
75 unsigned long mask;
76
77 if (irqno != IRQ_TIMER4 && irqno != IRQ_EINT8t23)
78 irqdbf2("s3c_irq_unmask %d\n", irqno);
79
80 irqno -= IRQ_EINT0;
81
82 mask = __raw_readl(S3C2410_INTMSK);
83 mask &= ~(1UL << irqno);
84 __raw_writel(mask, S3C2410_INTMSK);
85}
86
87struct irq_chip s3c_irq_level_chip = {
88 .name = "s3c-level",
89 .irq_ack = s3c_irq_maskack,
90 .irq_mask = s3c_irq_mask,
91 .irq_unmask = s3c_irq_unmask,
92 .irq_set_wake = s3c_irq_wake
93}; 53};
94 54
95struct irq_chip s3c_irq_chip = { 55/*
96 .name = "s3c", 56 * Sructure holding the controller data
97 .irq_ack = s3c_irq_ack, 57 * @reg_pending register holding pending irqs
98 .irq_mask = s3c_irq_mask, 58 * @reg_intpnd special register intpnd in main intc
99 .irq_unmask = s3c_irq_unmask, 59 * @reg_mask mask register
100 .irq_set_wake = s3c_irq_wake 60 * @domain irq_domain of the controller
61 * @parent parent controller for ext and sub irqs
62 * @irqs irq-data, always s3c_irq_data[32]
63 */
64struct s3c_irq_intc {
65 void __iomem *reg_pending;
66 void __iomem *reg_intpnd;
67 void __iomem *reg_mask;
68 struct irq_domain *domain;
69 struct s3c_irq_intc *parent;
70 struct s3c_irq_data *irqs;
101}; 71};
102 72
103static void 73static void s3c_irq_mask(struct irq_data *data)
104s3c_irqext_mask(struct irq_data *data)
105{ 74{
106 unsigned int irqno = data->irq - EXTINT_OFF; 75 struct s3c_irq_intc *intc = data->domain->host_data;
76 struct s3c_irq_intc *parent_intc = intc->parent;
77 struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
78 struct s3c_irq_data *parent_data;
107 unsigned long mask; 79 unsigned long mask;
80 unsigned int irqno;
81
82 mask = __raw_readl(intc->reg_mask);
83 mask |= (1UL << data->hwirq);
84 __raw_writel(mask, intc->reg_mask);
85
86 if (parent_intc && irq_data->parent_irq) {
87 parent_data = &parent_intc->irqs[irq_data->parent_irq];
108 88
109 mask = __raw_readl(S3C24XX_EINTMASK); 89 /* check to see if we need to mask the parent IRQ */
110 mask |= ( 1UL << irqno); 90 if ((mask & parent_data->sub_bits) == parent_data->sub_bits) {
111 __raw_writel(mask, S3C24XX_EINTMASK); 91 irqno = irq_find_mapping(parent_intc->domain,
92 irq_data->parent_irq);
93 s3c_irq_mask(irq_get_irq_data(irqno));
94 }
95 }
112} 96}
113 97
114static void 98static void s3c_irq_unmask(struct irq_data *data)
115s3c_irqext_ack(struct irq_data *data)
116{ 99{
117 unsigned long req; 100 struct s3c_irq_intc *intc = data->domain->host_data;
118 unsigned long bit; 101 struct s3c_irq_intc *parent_intc = intc->parent;
102 struct s3c_irq_data *irq_data = &intc->irqs[data->hwirq];
119 unsigned long mask; 103 unsigned long mask;
104 unsigned int irqno;
120 105
121 bit = 1UL << (data->irq - EXTINT_OFF); 106 mask = __raw_readl(intc->reg_mask);
122 107 mask &= ~(1UL << data->hwirq);
123 mask = __raw_readl(S3C24XX_EINTMASK); 108 __raw_writel(mask, intc->reg_mask);
124
125 __raw_writel(bit, S3C24XX_EINTPEND);
126
127 req = __raw_readl(S3C24XX_EINTPEND);
128 req &= ~mask;
129
130 /* not sure if we should be acking the parent irq... */
131 109
132 if (data->irq <= IRQ_EINT7) { 110 if (parent_intc && irq_data->parent_irq) {
133 if ((req & 0xf0) == 0) 111 irqno = irq_find_mapping(parent_intc->domain,
134 s3c_irq_ack(irq_get_irq_data(IRQ_EINT4t7)); 112 irq_data->parent_irq);
135 } else { 113 s3c_irq_unmask(irq_get_irq_data(irqno));
136 if ((req >> 8) == 0)
137 s3c_irq_ack(irq_get_irq_data(IRQ_EINT8t23));
138 } 114 }
139} 115}
140 116
141static void 117static inline void s3c_irq_ack(struct irq_data *data)
142s3c_irqext_unmask(struct irq_data *data)
143{ 118{
144 unsigned int irqno = data->irq - EXTINT_OFF; 119 struct s3c_irq_intc *intc = data->domain->host_data;
145 unsigned long mask; 120 unsigned long bitval = 1UL << data->hwirq;
146 121
147 mask = __raw_readl(S3C24XX_EINTMASK); 122 __raw_writel(bitval, intc->reg_pending);
148 mask &= ~(1UL << irqno); 123 if (intc->reg_intpnd)
149 __raw_writel(mask, S3C24XX_EINTMASK); 124 __raw_writel(bitval, intc->reg_intpnd);
150} 125}
151 126
152int 127static int s3c_irqext_type_set(void __iomem *gpcon_reg,
153s3c_irqext_type(struct irq_data *data, unsigned int type) 128 void __iomem *extint_reg,
129 unsigned long gpcon_offset,
130 unsigned long extint_offset,
131 unsigned int type)
154{ 132{
155 void __iomem *extint_reg;
156 void __iomem *gpcon_reg;
157 unsigned long gpcon_offset, extint_offset;
158 unsigned long newvalue = 0, value; 133 unsigned long newvalue = 0, value;
159 134
160 if ((data->irq >= IRQ_EINT0) && (data->irq <= IRQ_EINT3)) {
161 gpcon_reg = S3C2410_GPFCON;
162 extint_reg = S3C24XX_EXTINT0;
163 gpcon_offset = (data->irq - IRQ_EINT0) * 2;
164 extint_offset = (data->irq - IRQ_EINT0) * 4;
165 } else if ((data->irq >= IRQ_EINT4) && (data->irq <= IRQ_EINT7)) {
166 gpcon_reg = S3C2410_GPFCON;
167 extint_reg = S3C24XX_EXTINT0;
168 gpcon_offset = (data->irq - (EXTINT_OFF)) * 2;
169 extint_offset = (data->irq - (EXTINT_OFF)) * 4;
170 } else if ((data->irq >= IRQ_EINT8) && (data->irq <= IRQ_EINT15)) {
171 gpcon_reg = S3C2410_GPGCON;
172 extint_reg = S3C24XX_EXTINT1;
173 gpcon_offset = (data->irq - IRQ_EINT8) * 2;
174 extint_offset = (data->irq - IRQ_EINT8) * 4;
175 } else if ((data->irq >= IRQ_EINT16) && (data->irq <= IRQ_EINT23)) {
176 gpcon_reg = S3C2410_GPGCON;
177 extint_reg = S3C24XX_EXTINT2;
178 gpcon_offset = (data->irq - IRQ_EINT8) * 2;
179 extint_offset = (data->irq - IRQ_EINT16) * 4;
180 } else {
181 return -1;
182 }
183
184 /* Set the GPIO to external interrupt mode */ 135 /* Set the GPIO to external interrupt mode */
185 value = __raw_readl(gpcon_reg); 136 value = __raw_readl(gpcon_reg);
186 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); 137 value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
@@ -190,7 +141,7 @@ s3c_irqext_type(struct irq_data *data, unsigned int type)
190 switch (type) 141 switch (type)
191 { 142 {
192 case IRQ_TYPE_NONE: 143 case IRQ_TYPE_NONE:
193 printk(KERN_WARNING "No edge setting!\n"); 144 pr_warn("No edge setting!\n");
194 break; 145 break;
195 146
196 case IRQ_TYPE_EDGE_RISING: 147 case IRQ_TYPE_EDGE_RISING:
@@ -214,8 +165,8 @@ s3c_irqext_type(struct irq_data *data, unsigned int type)
214 break; 165 break;
215 166
216 default: 167 default:
217 printk(KERN_ERR "No such irq type %d", type); 168 pr_err("No such irq type %d", type);
218 return -1; 169 return -EINVAL;
219 } 170 }
220 171
221 value = __raw_readl(extint_reg); 172 value = __raw_readl(extint_reg);
@@ -225,265 +176,113 @@ s3c_irqext_type(struct irq_data *data, unsigned int type)
225 return 0; 176 return 0;
226} 177}
227 178
228static struct irq_chip s3c_irqext_chip = { 179/* FIXME: make static when it's out of plat-samsung/irq.h */
229 .name = "s3c-ext", 180int s3c_irqext_type(struct irq_data *data, unsigned int type)
230 .irq_mask = s3c_irqext_mask,
231 .irq_unmask = s3c_irqext_unmask,
232 .irq_ack = s3c_irqext_ack,
233 .irq_set_type = s3c_irqext_type,
234 .irq_set_wake = s3c_irqext_wake
235};
236
237static struct irq_chip s3c_irq_eint0t4 = {
238 .name = "s3c-ext0",
239 .irq_ack = s3c_irq_ack,
240 .irq_mask = s3c_irq_mask,
241 .irq_unmask = s3c_irq_unmask,
242 .irq_set_wake = s3c_irq_wake,
243 .irq_set_type = s3c_irqext_type,
244};
245
246/* mask values for the parent registers for each of the interrupt types */
247
248#define INTMSK_UART0 (1UL << (IRQ_UART0 - IRQ_EINT0))
249#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
250#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
251#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
252
253
254/* UART0 */
255
256static void
257s3c_irq_uart0_mask(struct irq_data *data)
258{ 181{
259 s3c_irqsub_mask(data->irq, INTMSK_UART0, 7); 182 void __iomem *extint_reg;
260} 183 void __iomem *gpcon_reg;
184 unsigned long gpcon_offset, extint_offset;
261 185
262static void 186 if ((data->hwirq >= 4) && (data->hwirq <= 7)) {
263s3c_irq_uart0_unmask(struct irq_data *data) 187 gpcon_reg = S3C2410_GPFCON;
264{ 188 extint_reg = S3C24XX_EXTINT0;
265 s3c_irqsub_unmask(data->irq, INTMSK_UART0); 189 gpcon_offset = (data->hwirq) * 2;
266} 190 extint_offset = (data->hwirq) * 4;
191 } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) {
192 gpcon_reg = S3C2410_GPGCON;
193 extint_reg = S3C24XX_EXTINT1;
194 gpcon_offset = (data->hwirq - 8) * 2;
195 extint_offset = (data->hwirq - 8) * 4;
196 } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) {
197 gpcon_reg = S3C2410_GPGCON;
198 extint_reg = S3C24XX_EXTINT2;
199 gpcon_offset = (data->hwirq - 8) * 2;
200 extint_offset = (data->hwirq - 16) * 4;
201 } else {
202 return -EINVAL;
203 }
267 204
268static void 205 return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
269s3c_irq_uart0_ack(struct irq_data *data) 206 extint_offset, type);
270{
271 s3c_irqsub_maskack(data->irq, INTMSK_UART0, 7);
272} 207}
273 208
274static struct irq_chip s3c_irq_uart0 = { 209static int s3c_irqext0_type(struct irq_data *data, unsigned int type)
275 .name = "s3c-uart0",
276 .irq_mask = s3c_irq_uart0_mask,
277 .irq_unmask = s3c_irq_uart0_unmask,
278 .irq_ack = s3c_irq_uart0_ack,
279};
280
281/* UART1 */
282
283static void
284s3c_irq_uart1_mask(struct irq_data *data)
285{ 210{
286 s3c_irqsub_mask(data->irq, INTMSK_UART1, 7 << 3); 211 void __iomem *extint_reg;
287} 212 void __iomem *gpcon_reg;
213 unsigned long gpcon_offset, extint_offset;
288 214
289static void 215 if ((data->hwirq >= 0) && (data->hwirq <= 3)) {
290s3c_irq_uart1_unmask(struct irq_data *data) 216 gpcon_reg = S3C2410_GPFCON;
291{ 217 extint_reg = S3C24XX_EXTINT0;
292 s3c_irqsub_unmask(data->irq, INTMSK_UART1); 218 gpcon_offset = (data->hwirq) * 2;
293} 219 extint_offset = (data->hwirq) * 4;
220 } else {
221 return -EINVAL;
222 }
294 223
295static void 224 return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
296s3c_irq_uart1_ack(struct irq_data *data) 225 extint_offset, type);
297{
298 s3c_irqsub_maskack(data->irq, INTMSK_UART1, 7 << 3);
299} 226}
300 227
301static struct irq_chip s3c_irq_uart1 = { 228struct irq_chip s3c_irq_chip = {
302 .name = "s3c-uart1", 229 .name = "s3c",
303 .irq_mask = s3c_irq_uart1_mask, 230 .irq_ack = s3c_irq_ack,
304 .irq_unmask = s3c_irq_uart1_unmask, 231 .irq_mask = s3c_irq_mask,
305 .irq_ack = s3c_irq_uart1_ack, 232 .irq_unmask = s3c_irq_unmask,
233 .irq_set_wake = s3c_irq_wake
306}; 234};
307 235
308/* UART2 */ 236struct irq_chip s3c_irq_level_chip = {
309 237 .name = "s3c-level",
310static void 238 .irq_mask = s3c_irq_mask,
311s3c_irq_uart2_mask(struct irq_data *data) 239 .irq_unmask = s3c_irq_unmask,
312{ 240 .irq_ack = s3c_irq_ack,
313 s3c_irqsub_mask(data->irq, INTMSK_UART2, 7 << 6);
314}
315
316static void
317s3c_irq_uart2_unmask(struct irq_data *data)
318{
319 s3c_irqsub_unmask(data->irq, INTMSK_UART2);
320}
321
322static void
323s3c_irq_uart2_ack(struct irq_data *data)
324{
325 s3c_irqsub_maskack(data->irq, INTMSK_UART2, 7 << 6);
326}
327
328static struct irq_chip s3c_irq_uart2 = {
329 .name = "s3c-uart2",
330 .irq_mask = s3c_irq_uart2_mask,
331 .irq_unmask = s3c_irq_uart2_unmask,
332 .irq_ack = s3c_irq_uart2_ack,
333}; 241};
334 242
335/* ADC and Touchscreen */ 243static struct irq_chip s3c_irqext_chip = {
336 244 .name = "s3c-ext",
337static void 245 .irq_mask = s3c_irq_mask,
338s3c_irq_adc_mask(struct irq_data *d) 246 .irq_unmask = s3c_irq_unmask,
339{ 247 .irq_ack = s3c_irq_ack,
340 s3c_irqsub_mask(d->irq, INTMSK_ADCPARENT, 3 << 9); 248 .irq_set_type = s3c_irqext_type,
341} 249 .irq_set_wake = s3c_irqext_wake
342
343static void
344s3c_irq_adc_unmask(struct irq_data *d)
345{
346 s3c_irqsub_unmask(d->irq, INTMSK_ADCPARENT);
347}
348
349static void
350s3c_irq_adc_ack(struct irq_data *d)
351{
352 s3c_irqsub_ack(d->irq, INTMSK_ADCPARENT, 3 << 9);
353}
354
355static struct irq_chip s3c_irq_adc = {
356 .name = "s3c-adc",
357 .irq_mask = s3c_irq_adc_mask,
358 .irq_unmask = s3c_irq_adc_unmask,
359 .irq_ack = s3c_irq_adc_ack,
360}; 250};
361 251
362/* irq demux for adc */ 252static struct irq_chip s3c_irq_eint0t4 = {
363static void s3c_irq_demux_adc(unsigned int irq, 253 .name = "s3c-ext0",
364 struct irq_desc *desc) 254 .irq_ack = s3c_irq_ack,
365{ 255 .irq_mask = s3c_irq_mask,
366 unsigned int subsrc, submsk; 256 .irq_unmask = s3c_irq_unmask,
367 unsigned int offset = 9; 257 .irq_set_wake = s3c_irq_wake,
368 258 .irq_set_type = s3c_irqext0_type,
369 /* read the current pending interrupts, and the mask 259};
370 * for what it is available */
371
372 subsrc = __raw_readl(S3C2410_SUBSRCPND);
373 submsk = __raw_readl(S3C2410_INTSUBMSK);
374
375 subsrc &= ~submsk;
376 subsrc >>= offset;
377 subsrc &= 3;
378
379 if (subsrc != 0) {
380 if (subsrc & 1) {
381 generic_handle_irq(IRQ_TC);
382 }
383 if (subsrc & 2) {
384 generic_handle_irq(IRQ_ADC);
385 }
386 }
387}
388
389static void s3c_irq_demux_uart(unsigned int start)
390{
391 unsigned int subsrc, submsk;
392 unsigned int offset = start - IRQ_S3CUART_RX0;
393
394 /* read the current pending interrupts, and the mask
395 * for what it is available */
396
397 subsrc = __raw_readl(S3C2410_SUBSRCPND);
398 submsk = __raw_readl(S3C2410_INTSUBMSK);
399
400 irqdbf2("s3c_irq_demux_uart: start=%d (%d), subsrc=0x%08x,0x%08x\n",
401 start, offset, subsrc, submsk);
402
403 subsrc &= ~submsk;
404 subsrc >>= offset;
405 subsrc &= 7;
406
407 if (subsrc != 0) {
408 if (subsrc & 1)
409 generic_handle_irq(start);
410
411 if (subsrc & 2)
412 generic_handle_irq(start+1);
413
414 if (subsrc & 4)
415 generic_handle_irq(start+2);
416 }
417}
418
419/* uart demux entry points */
420
421static void
422s3c_irq_demux_uart0(unsigned int irq,
423 struct irq_desc *desc)
424{
425 irq = irq;
426 s3c_irq_demux_uart(IRQ_S3CUART_RX0);
427}
428
429static void
430s3c_irq_demux_uart1(unsigned int irq,
431 struct irq_desc *desc)
432{
433 irq = irq;
434 s3c_irq_demux_uart(IRQ_S3CUART_RX1);
435}
436
437static void
438s3c_irq_demux_uart2(unsigned int irq,
439 struct irq_desc *desc)
440{
441 irq = irq;
442 s3c_irq_demux_uart(IRQ_S3CUART_RX2);
443}
444 260
445static void 261static void s3c_irq_demux(unsigned int irq, struct irq_desc *desc)
446s3c_irq_demux_extint8(unsigned int irq,
447 struct irq_desc *desc)
448{ 262{
449 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND); 263 struct irq_chip *chip = irq_desc_get_chip(desc);
450 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK); 264 struct s3c_irq_intc *intc = desc->irq_data.domain->host_data;
451 265 struct s3c_irq_data *irq_data = &intc->irqs[desc->irq_data.hwirq];
452 eintpnd &= ~eintmsk; 266 struct s3c_irq_intc *sub_intc = irq_data->sub_intc;
453 eintpnd &= ~0xff; /* ignore lower irqs */ 267 unsigned long src;
454 268 unsigned long msk;
455 /* we may as well handle all the pending IRQs here */ 269 unsigned int n;
456 270
457 while (eintpnd) { 271 chained_irq_enter(chip, desc);
458 irq = __ffs(eintpnd); 272
459 eintpnd &= ~(1<<irq); 273 src = __raw_readl(sub_intc->reg_pending);
460 274 msk = __raw_readl(sub_intc->reg_mask);
461 irq += (IRQ_EINT4 - 4); 275
462 generic_handle_irq(irq); 276 src &= ~msk;
277 src &= irq_data->sub_bits;
278
279 while (src) {
280 n = __ffs(src);
281 src &= ~(1 << n);
282 generic_handle_irq(irq_find_mapping(sub_intc->domain, n));
463 } 283 }
464 284
465} 285 chained_irq_exit(chip, desc);
466
467static void
468s3c_irq_demux_extint4t7(unsigned int irq,
469 struct irq_desc *desc)
470{
471 unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
472 unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
473
474 eintpnd &= ~eintmsk;
475 eintpnd &= 0xff; /* only lower irqs */
476
477 /* we may as well handle all the pending IRQs here */
478
479 while (eintpnd) {
480 irq = __ffs(eintpnd);
481 eintpnd &= ~(1<<irq);
482
483 irq += (IRQ_EINT4 - 4);
484
485 generic_handle_irq(irq);
486 }
487} 286}
488 287
489#ifdef CONFIG_FIQ 288#ifdef CONFIG_FIQ
@@ -519,155 +318,314 @@ int s3c24xx_set_fiq(unsigned int irq, bool on)
519EXPORT_SYMBOL_GPL(s3c24xx_set_fiq); 318EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
520#endif 319#endif
521 320
522 321static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
523/* s3c24xx_init_irq 322 irq_hw_number_t hw)
524 *
525 * Initialise S3C2410 IRQ system
526*/
527
528void __init s3c24xx_init_irq(void)
529{ 323{
530 unsigned long pend; 324 struct s3c_irq_intc *intc = h->host_data;
531 unsigned long last; 325 struct s3c_irq_data *irq_data = &intc->irqs[hw];
532 int irqno; 326 struct s3c_irq_intc *parent_intc;
533 int i; 327 struct s3c_irq_data *parent_irq_data;
534 328 unsigned int irqno;
535#ifdef CONFIG_FIQ 329
536 init_FIQ(FIQ_START); 330 if (!intc) {
537#endif 331 pr_err("irq-s3c24xx: no controller found for hwirq %lu\n", hw);
538 332 return -EINVAL;
539 irqdbf("s3c2410_init_irq: clearing interrupt status flags\n"); 333 }
540
541 /* first, clear all interrupts pending... */
542 334
543 last = 0; 335 if (!irq_data) {
544 for (i = 0; i < 4; i++) { 336 pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n", hw);
545 pend = __raw_readl(S3C24XX_EINTPEND); 337 return -EINVAL;
338 }
546 339
547 if (pend == 0 || pend == last) 340 /* attach controller pointer to irq_data */
548 break; 341 irq_data->intc = intc;
549 342
550 __raw_writel(pend, S3C24XX_EINTPEND); 343 /* set handler and flags */
551 printk("irq: clearing pending ext status %08x\n", (int)pend); 344 switch (irq_data->type) {
552 last = pend; 345 case S3C_IRQTYPE_NONE:
346 return 0;
347 case S3C_IRQTYPE_EINT:
348 if (irq_data->parent_irq)
349 irq_set_chip_and_handler(virq, &s3c_irqext_chip,
350 handle_edge_irq);
351 else
352 irq_set_chip_and_handler(virq, &s3c_irq_eint0t4,
353 handle_edge_irq);
354 break;
355 case S3C_IRQTYPE_EDGE:
356 if (irq_data->parent_irq)
357 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
358 handle_edge_irq);
359 else
360 irq_set_chip_and_handler(virq, &s3c_irq_chip,
361 handle_edge_irq);
362 break;
363 case S3C_IRQTYPE_LEVEL:
364 if (irq_data->parent_irq)
365 irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
366 handle_level_irq);
367 else
368 irq_set_chip_and_handler(virq, &s3c_irq_chip,
369 handle_level_irq);
370 break;
371 default:
372 pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type);
373 return -EINVAL;
553 } 374 }
375 set_irq_flags(virq, IRQF_VALID);
376
377 if (irq_data->parent_irq) {
378 parent_intc = intc->parent;
379 if (!parent_intc) {
380 pr_err("irq-s3c24xx: no parent controller found for hwirq %lu\n",
381 hw);
382 goto err;
383 }
554 384
555 last = 0; 385 parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
556 for (i = 0; i < 4; i++) { 386 if (!irq_data) {
557 pend = __raw_readl(S3C2410_INTPND); 387 pr_err("irq-s3c24xx: no irq data found for hwirq %lu\n",
388 hw);
389 goto err;
390 }
558 391
559 if (pend == 0 || pend == last) 392 parent_irq_data->sub_intc = intc;
560 break; 393 parent_irq_data->sub_bits |= (1UL << hw);
561 394
562 __raw_writel(pend, S3C2410_SRCPND); 395 /* attach the demuxer to the parent irq */
563 __raw_writel(pend, S3C2410_INTPND); 396 irqno = irq_find_mapping(parent_intc->domain,
564 printk("irq: clearing pending status %08x\n", (int)pend); 397 irq_data->parent_irq);
565 last = pend; 398 if (!irqno) {
399 pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n",
400 irq_data->parent_irq);
401 goto err;
402 }
403 irq_set_chained_handler(irqno, s3c_irq_demux);
566 } 404 }
567 405
568 last = 0; 406 return 0;
569 for (i = 0; i < 4; i++) {
570 pend = __raw_readl(S3C2410_SUBSRCPND);
571 407
572 if (pend == 0 || pend == last) 408err:
573 break; 409 set_irq_flags(virq, 0);
574 410
575 printk("irq: clearing subpending status %08x\n", (int)pend); 411 /* the only error can result from bad mapping data*/
576 __raw_writel(pend, S3C2410_SUBSRCPND); 412 return -EINVAL;
577 last = pend; 413}
578 }
579 414
580 /* register the main interrupts */ 415static struct irq_domain_ops s3c24xx_irq_ops = {
416 .map = s3c24xx_irq_map,
417 .xlate = irq_domain_xlate_twocell,
418};
581 419
582 irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); 420static void s3c24xx_clear_intc(struct s3c_irq_intc *intc)
421{
422 void __iomem *reg_source;
423 unsigned long pend;
424 unsigned long last;
425 int i;
583 426
584 for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) { 427 /* if intpnd is set, read the next pending irq from there */
585 /* set all the s3c2410 internal irqs */ 428 reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending;
586 429
587 switch (irqno) { 430 last = 0;
588 /* deal with the special IRQs (cascaded) */ 431 for (i = 0; i < 4; i++) {
432 pend = __raw_readl(reg_source);
589 433
590 case IRQ_EINT4t7: 434 if (pend == 0 || pend == last)
591 case IRQ_EINT8t23:
592 case IRQ_UART0:
593 case IRQ_UART1:
594 case IRQ_UART2:
595 case IRQ_ADCPARENT:
596 irq_set_chip_and_handler(irqno, &s3c_irq_level_chip,
597 handle_level_irq);
598 break; 435 break;
599 436
600 case IRQ_RESERVED6: 437 __raw_writel(pend, intc->reg_pending);
601 case IRQ_RESERVED24: 438 if (intc->reg_intpnd)
602 /* no IRQ here */ 439 __raw_writel(pend, intc->reg_intpnd);
603 break;
604 440
605 default: 441 pr_info("irq: clearing pending status %08x\n", (int)pend);
606 //irqdbf("registering irq %d (s3c irq)\n", irqno); 442 last = pend;
607 irq_set_chip_and_handler(irqno, &s3c_irq_chip,
608 handle_edge_irq);
609 set_irq_flags(irqno, IRQF_VALID);
610 }
611 } 443 }
444}
612 445
613 /* setup the cascade irq handlers */ 446struct s3c_irq_intc *s3c24xx_init_intc(struct device_node *np,
614 447 struct s3c_irq_data *irq_data,
615 irq_set_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7); 448 struct s3c_irq_intc *parent,
616 irq_set_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8); 449 unsigned long address)
450{
451 struct s3c_irq_intc *intc;
452 void __iomem *base = (void *)0xf6000000; /* static mapping */
453 int irq_num;
454 int irq_start;
455 int irq_offset;
456 int ret;
457
458 intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
459 if (!intc)
460 return ERR_PTR(-ENOMEM);
461
462 intc->irqs = irq_data;
463
464 if (parent)
465 intc->parent = parent;
466
467 /* select the correct data for the controller.
468 * Need to hard code the irq num start and offset
469 * to preserve the static mapping for now
470 */
471 switch (address) {
472 case 0x4a000000:
473 pr_debug("irq: found main intc\n");
474 intc->reg_pending = base;
475 intc->reg_mask = base + 0x08;
476 intc->reg_intpnd = base + 0x10;
477 irq_num = 32;
478 irq_start = S3C2410_IRQ(0);
479 irq_offset = 0;
480 break;
481 case 0x4a000018:
482 pr_debug("irq: found subintc\n");
483 intc->reg_pending = base + 0x18;
484 intc->reg_mask = base + 0x1c;
485 irq_num = 29;
486 irq_start = S3C2410_IRQSUB(0);
487 irq_offset = 0;
488 break;
489 case 0x4a000040:
490 pr_debug("irq: found intc2\n");
491 intc->reg_pending = base + 0x40;
492 intc->reg_mask = base + 0x48;
493 intc->reg_intpnd = base + 0x50;
494 irq_num = 8;
495 irq_start = S3C2416_IRQ(0);
496 irq_offset = 0;
497 break;
498 case 0x560000a4:
499 pr_debug("irq: found eintc\n");
500 base = (void *)0xfd000000;
501
502 intc->reg_mask = base + 0xa4;
503 intc->reg_pending = base + 0x08;
504 irq_num = 20;
505 irq_start = S3C2410_IRQ(32);
506 irq_offset = 4;
507 break;
508 default:
509 pr_err("irq: unsupported controller address\n");
510 ret = -EINVAL;
511 goto err;
512 }
617 513
618 irq_set_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); 514 /* now that all the data is complete, init the irq-domain */
619 irq_set_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); 515 s3c24xx_clear_intc(intc);
620 irq_set_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); 516 intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
621 irq_set_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); 517 irq_offset, &s3c24xx_irq_ops,
518 intc);
519 if (!intc->domain) {
520 pr_err("irq: could not create irq-domain\n");
521 ret = -EINVAL;
522 goto err;
523 }
622 524
623 /* external interrupts */ 525 return intc;
624 526
625 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { 527err:
626 irqdbf("registering irq %d (ext int)\n", irqno); 528 kfree(intc);
627 irq_set_chip_and_handler(irqno, &s3c_irq_eint0t4, 529 return ERR_PTR(ret);
628 handle_edge_irq); 530}
629 set_irq_flags(irqno, IRQF_VALID);
630 }
631 531
632 for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) { 532/* s3c24xx_init_irq
633 irqdbf("registering irq %d (extended s3c irq)\n", irqno); 533 *
634 irq_set_chip_and_handler(irqno, &s3c_irqext_chip, 534 * Initialise S3C2410 IRQ system
635 handle_edge_irq); 535*/
636 set_irq_flags(irqno, IRQF_VALID);
637 }
638 536
639 /* register the uart interrupts */ 537static struct s3c_irq_data init_base[32] = {
538 { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
539 { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
540 { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
541 { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
542 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
543 { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
544 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
545 { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
546 { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
547 { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
548 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
549 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
550 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
551 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
552 { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
553 { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
554 { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
555 { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
556 { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
557 { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
558 { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
559 { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
560 { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
561 { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
562 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
563 { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
564 { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
565 { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
566 { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
567 { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
568 { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
569 { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
570};
640 571
641 irqdbf("s3c2410: registering external interrupts\n"); 572static struct s3c_irq_data init_eint[32] = {
573 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
574 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
575 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
576 { .type = S3C_IRQTYPE_NONE, }, /* reserved */
577 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
578 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
579 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
580 { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
581 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
582 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
583 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
584 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
585 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
586 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
587 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
588 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
589 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
590 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
591 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
592 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
593 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
594 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
595 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
596 { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
597};
642 598
643 for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) { 599static struct s3c_irq_data init_subint[32] = {
644 irqdbf("registering irq %d (s3c uart0 irq)\n", irqno); 600 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
645 irq_set_chip_and_handler(irqno, &s3c_irq_uart0, 601 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
646 handle_level_irq); 602 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
647 set_irq_flags(irqno, IRQF_VALID); 603 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
648 } 604 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
605 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
606 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
607 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
608 { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
609 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
610 { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
611};
649 612
650 for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) { 613void __init s3c24xx_init_irq(void)
651 irqdbf("registering irq %d (s3c uart1 irq)\n", irqno); 614{
652 irq_set_chip_and_handler(irqno, &s3c_irq_uart1, 615 struct s3c_irq_intc *main_intc;
653 handle_level_irq);
654 set_irq_flags(irqno, IRQF_VALID);
655 }
656 616
657 for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) { 617#ifdef CONFIG_FIQ
658 irqdbf("registering irq %d (s3c uart2 irq)\n", irqno); 618 init_FIQ(FIQ_START);
659 irq_set_chip_and_handler(irqno, &s3c_irq_uart2, 619#endif
660 handle_level_irq);
661 set_irq_flags(irqno, IRQF_VALID);
662 }
663 620
664 for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) { 621 main_intc = s3c24xx_init_intc(NULL, &init_base[0], NULL, 0x4a000000);
665 irqdbf("registering irq %d (s3c adc irq)\n", irqno); 622 if (IS_ERR(main_intc)) {
666 irq_set_chip_and_handler(irqno, &s3c_irq_adc, handle_edge_irq); 623 pr_err("irq: could not create main interrupt controller\n");
667 set_irq_flags(irqno, IRQF_VALID); 624 return;
668 } 625 }
669 626
670 irqdbf("s3c2410: registered interrupt handlers\n"); 627 s3c24xx_init_intc(NULL, &init_subint[0], main_intc, 0x4a000018);
628 s3c24xx_init_intc(NULL, &init_eint[0], main_intc, 0x560000a4);
671} 629}
672 630
673struct syscore_ops s3c24xx_irq_syscore_ops = { 631struct syscore_ops s3c24xx_irq_syscore_ops = {