1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * S3C24XX IRQ handling
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2003-2004 Simtec Electronics
6*4882a593Smuzhiyun * Ben Dooks <ben@simtec.co.uk>
7*4882a593Smuzhiyun * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/init.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/io.h>
14*4882a593Smuzhiyun #include <linux/err.h>
15*4882a593Smuzhiyun #include <linux/interrupt.h>
16*4882a593Smuzhiyun #include <linux/ioport.h>
17*4882a593Smuzhiyun #include <linux/device.h>
18*4882a593Smuzhiyun #include <linux/irqdomain.h>
19*4882a593Smuzhiyun #include <linux/irqchip.h>
20*4882a593Smuzhiyun #include <linux/irqchip/chained_irq.h>
21*4882a593Smuzhiyun #include <linux/of.h>
22*4882a593Smuzhiyun #include <linux/of_irq.h>
23*4882a593Smuzhiyun #include <linux/of_address.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <asm/exception.h>
26*4882a593Smuzhiyun #include <asm/mach/irq.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include <mach/irqs.h>
29*4882a593Smuzhiyun #include "regs-irq.h"
30*4882a593Smuzhiyun #include "regs-gpio.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include "cpu.h"
33*4882a593Smuzhiyun #include "regs-irqtype.h"
34*4882a593Smuzhiyun #include "pm.h"
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define S3C_IRQTYPE_NONE 0
37*4882a593Smuzhiyun #define S3C_IRQTYPE_EINT 1
38*4882a593Smuzhiyun #define S3C_IRQTYPE_EDGE 2
39*4882a593Smuzhiyun #define S3C_IRQTYPE_LEVEL 3
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun struct s3c_irq_data {
42*4882a593Smuzhiyun unsigned int type;
43*4882a593Smuzhiyun unsigned long offset;
44*4882a593Smuzhiyun unsigned long parent_irq;
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* data gets filled during init */
47*4882a593Smuzhiyun struct s3c_irq_intc *intc;
48*4882a593Smuzhiyun unsigned long sub_bits;
49*4882a593Smuzhiyun struct s3c_irq_intc *sub_intc;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun * Structure holding the controller data
54*4882a593Smuzhiyun * @reg_pending register holding pending irqs
55*4882a593Smuzhiyun * @reg_intpnd special register intpnd in main intc
56*4882a593Smuzhiyun * @reg_mask mask register
57*4882a593Smuzhiyun * @domain irq_domain of the controller
58*4882a593Smuzhiyun * @parent parent controller for ext and sub irqs
59*4882a593Smuzhiyun * @irqs irq-data, always s3c_irq_data[32]
60*4882a593Smuzhiyun */
61*4882a593Smuzhiyun struct s3c_irq_intc {
62*4882a593Smuzhiyun void __iomem *reg_pending;
63*4882a593Smuzhiyun void __iomem *reg_intpnd;
64*4882a593Smuzhiyun void __iomem *reg_mask;
65*4882a593Smuzhiyun struct irq_domain *domain;
66*4882a593Smuzhiyun struct s3c_irq_intc *parent;
67*4882a593Smuzhiyun struct s3c_irq_data *irqs;
68*4882a593Smuzhiyun };
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * Array holding pointers to the global controller structs
72*4882a593Smuzhiyun * [0] ... main_intc
73*4882a593Smuzhiyun * [1] ... sub_intc
74*4882a593Smuzhiyun * [2] ... main_intc2 on s3c2416
75*4882a593Smuzhiyun */
76*4882a593Smuzhiyun static struct s3c_irq_intc *s3c_intc[3];
77*4882a593Smuzhiyun
s3c_irq_mask(struct irq_data * data)78*4882a593Smuzhiyun static void s3c_irq_mask(struct irq_data *data)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
81*4882a593Smuzhiyun struct s3c_irq_intc *intc = irq_data->intc;
82*4882a593Smuzhiyun struct s3c_irq_intc *parent_intc = intc->parent;
83*4882a593Smuzhiyun struct s3c_irq_data *parent_data;
84*4882a593Smuzhiyun unsigned long mask;
85*4882a593Smuzhiyun unsigned int irqno;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun mask = readl_relaxed(intc->reg_mask);
88*4882a593Smuzhiyun mask |= (1UL << irq_data->offset);
89*4882a593Smuzhiyun writel_relaxed(mask, intc->reg_mask);
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (parent_intc) {
92*4882a593Smuzhiyun parent_data = &parent_intc->irqs[irq_data->parent_irq];
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* check to see if we need to mask the parent IRQ
95*4882a593Smuzhiyun * The parent_irq is always in main_intc, so the hwirq
96*4882a593Smuzhiyun * for find_mapping does not need an offset in any case.
97*4882a593Smuzhiyun */
98*4882a593Smuzhiyun if ((mask & parent_data->sub_bits) == parent_data->sub_bits) {
99*4882a593Smuzhiyun irqno = irq_find_mapping(parent_intc->domain,
100*4882a593Smuzhiyun irq_data->parent_irq);
101*4882a593Smuzhiyun s3c_irq_mask(irq_get_irq_data(irqno));
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
s3c_irq_unmask(struct irq_data * data)106*4882a593Smuzhiyun static void s3c_irq_unmask(struct irq_data *data)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
109*4882a593Smuzhiyun struct s3c_irq_intc *intc = irq_data->intc;
110*4882a593Smuzhiyun struct s3c_irq_intc *parent_intc = intc->parent;
111*4882a593Smuzhiyun unsigned long mask;
112*4882a593Smuzhiyun unsigned int irqno;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun mask = readl_relaxed(intc->reg_mask);
115*4882a593Smuzhiyun mask &= ~(1UL << irq_data->offset);
116*4882a593Smuzhiyun writel_relaxed(mask, intc->reg_mask);
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun if (parent_intc) {
119*4882a593Smuzhiyun irqno = irq_find_mapping(parent_intc->domain,
120*4882a593Smuzhiyun irq_data->parent_irq);
121*4882a593Smuzhiyun s3c_irq_unmask(irq_get_irq_data(irqno));
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
s3c_irq_ack(struct irq_data * data)125*4882a593Smuzhiyun static inline void s3c_irq_ack(struct irq_data *data)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data);
128*4882a593Smuzhiyun struct s3c_irq_intc *intc = irq_data->intc;
129*4882a593Smuzhiyun unsigned long bitval = 1UL << irq_data->offset;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun writel_relaxed(bitval, intc->reg_pending);
132*4882a593Smuzhiyun if (intc->reg_intpnd)
133*4882a593Smuzhiyun writel_relaxed(bitval, intc->reg_intpnd);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
s3c_irq_type(struct irq_data * data,unsigned int type)136*4882a593Smuzhiyun static int s3c_irq_type(struct irq_data *data, unsigned int type)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun switch (type) {
139*4882a593Smuzhiyun case IRQ_TYPE_NONE:
140*4882a593Smuzhiyun break;
141*4882a593Smuzhiyun case IRQ_TYPE_EDGE_RISING:
142*4882a593Smuzhiyun case IRQ_TYPE_EDGE_FALLING:
143*4882a593Smuzhiyun case IRQ_TYPE_EDGE_BOTH:
144*4882a593Smuzhiyun irq_set_handler(data->irq, handle_edge_irq);
145*4882a593Smuzhiyun break;
146*4882a593Smuzhiyun case IRQ_TYPE_LEVEL_LOW:
147*4882a593Smuzhiyun case IRQ_TYPE_LEVEL_HIGH:
148*4882a593Smuzhiyun irq_set_handler(data->irq, handle_level_irq);
149*4882a593Smuzhiyun break;
150*4882a593Smuzhiyun default:
151*4882a593Smuzhiyun pr_err("No such irq type %d\n", type);
152*4882a593Smuzhiyun return -EINVAL;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun return 0;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
s3c_irqext_type_set(void __iomem * gpcon_reg,void __iomem * extint_reg,unsigned long gpcon_offset,unsigned long extint_offset,unsigned int type)158*4882a593Smuzhiyun static int s3c_irqext_type_set(void __iomem *gpcon_reg,
159*4882a593Smuzhiyun void __iomem *extint_reg,
160*4882a593Smuzhiyun unsigned long gpcon_offset,
161*4882a593Smuzhiyun unsigned long extint_offset,
162*4882a593Smuzhiyun unsigned int type)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun unsigned long newvalue = 0, value;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun /* Set the GPIO to external interrupt mode */
167*4882a593Smuzhiyun value = readl_relaxed(gpcon_reg);
168*4882a593Smuzhiyun value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);
169*4882a593Smuzhiyun writel_relaxed(value, gpcon_reg);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /* Set the external interrupt to pointed trigger type */
172*4882a593Smuzhiyun switch (type)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun case IRQ_TYPE_NONE:
175*4882a593Smuzhiyun pr_warn("No edge setting!\n");
176*4882a593Smuzhiyun break;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun case IRQ_TYPE_EDGE_RISING:
179*4882a593Smuzhiyun newvalue = S3C2410_EXTINT_RISEEDGE;
180*4882a593Smuzhiyun break;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun case IRQ_TYPE_EDGE_FALLING:
183*4882a593Smuzhiyun newvalue = S3C2410_EXTINT_FALLEDGE;
184*4882a593Smuzhiyun break;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun case IRQ_TYPE_EDGE_BOTH:
187*4882a593Smuzhiyun newvalue = S3C2410_EXTINT_BOTHEDGE;
188*4882a593Smuzhiyun break;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun case IRQ_TYPE_LEVEL_LOW:
191*4882a593Smuzhiyun newvalue = S3C2410_EXTINT_LOWLEV;
192*4882a593Smuzhiyun break;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun case IRQ_TYPE_LEVEL_HIGH:
195*4882a593Smuzhiyun newvalue = S3C2410_EXTINT_HILEV;
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun default:
199*4882a593Smuzhiyun pr_err("No such irq type %d\n", type);
200*4882a593Smuzhiyun return -EINVAL;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun value = readl_relaxed(extint_reg);
204*4882a593Smuzhiyun value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
205*4882a593Smuzhiyun writel_relaxed(value, extint_reg);
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
s3c_irqext_type(struct irq_data * data,unsigned int type)210*4882a593Smuzhiyun static int s3c_irqext_type(struct irq_data *data, unsigned int type)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun void __iomem *extint_reg;
213*4882a593Smuzhiyun void __iomem *gpcon_reg;
214*4882a593Smuzhiyun unsigned long gpcon_offset, extint_offset;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun if ((data->hwirq >= 4) && (data->hwirq <= 7)) {
217*4882a593Smuzhiyun gpcon_reg = S3C2410_GPFCON;
218*4882a593Smuzhiyun extint_reg = S3C24XX_EXTINT0;
219*4882a593Smuzhiyun gpcon_offset = (data->hwirq) * 2;
220*4882a593Smuzhiyun extint_offset = (data->hwirq) * 4;
221*4882a593Smuzhiyun } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) {
222*4882a593Smuzhiyun gpcon_reg = S3C2410_GPGCON;
223*4882a593Smuzhiyun extint_reg = S3C24XX_EXTINT1;
224*4882a593Smuzhiyun gpcon_offset = (data->hwirq - 8) * 2;
225*4882a593Smuzhiyun extint_offset = (data->hwirq - 8) * 4;
226*4882a593Smuzhiyun } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) {
227*4882a593Smuzhiyun gpcon_reg = S3C2410_GPGCON;
228*4882a593Smuzhiyun extint_reg = S3C24XX_EXTINT2;
229*4882a593Smuzhiyun gpcon_offset = (data->hwirq - 8) * 2;
230*4882a593Smuzhiyun extint_offset = (data->hwirq - 16) * 4;
231*4882a593Smuzhiyun } else {
232*4882a593Smuzhiyun return -EINVAL;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
236*4882a593Smuzhiyun extint_offset, type);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
s3c_irqext0_type(struct irq_data * data,unsigned int type)239*4882a593Smuzhiyun static int s3c_irqext0_type(struct irq_data *data, unsigned int type)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun void __iomem *extint_reg;
242*4882a593Smuzhiyun void __iomem *gpcon_reg;
243*4882a593Smuzhiyun unsigned long gpcon_offset, extint_offset;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun if (data->hwirq <= 3) {
246*4882a593Smuzhiyun gpcon_reg = S3C2410_GPFCON;
247*4882a593Smuzhiyun extint_reg = S3C24XX_EXTINT0;
248*4882a593Smuzhiyun gpcon_offset = (data->hwirq) * 2;
249*4882a593Smuzhiyun extint_offset = (data->hwirq) * 4;
250*4882a593Smuzhiyun } else {
251*4882a593Smuzhiyun return -EINVAL;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset,
255*4882a593Smuzhiyun extint_offset, type);
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun static struct irq_chip s3c_irq_chip = {
259*4882a593Smuzhiyun .name = "s3c",
260*4882a593Smuzhiyun .irq_ack = s3c_irq_ack,
261*4882a593Smuzhiyun .irq_mask = s3c_irq_mask,
262*4882a593Smuzhiyun .irq_unmask = s3c_irq_unmask,
263*4882a593Smuzhiyun .irq_set_type = s3c_irq_type,
264*4882a593Smuzhiyun .irq_set_wake = s3c_irq_wake
265*4882a593Smuzhiyun };
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun static struct irq_chip s3c_irq_level_chip = {
268*4882a593Smuzhiyun .name = "s3c-level",
269*4882a593Smuzhiyun .irq_mask = s3c_irq_mask,
270*4882a593Smuzhiyun .irq_unmask = s3c_irq_unmask,
271*4882a593Smuzhiyun .irq_ack = s3c_irq_ack,
272*4882a593Smuzhiyun .irq_set_type = s3c_irq_type,
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun static struct irq_chip s3c_irqext_chip = {
276*4882a593Smuzhiyun .name = "s3c-ext",
277*4882a593Smuzhiyun .irq_mask = s3c_irq_mask,
278*4882a593Smuzhiyun .irq_unmask = s3c_irq_unmask,
279*4882a593Smuzhiyun .irq_ack = s3c_irq_ack,
280*4882a593Smuzhiyun .irq_set_type = s3c_irqext_type,
281*4882a593Smuzhiyun .irq_set_wake = s3c_irqext_wake
282*4882a593Smuzhiyun };
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun static struct irq_chip s3c_irq_eint0t4 = {
285*4882a593Smuzhiyun .name = "s3c-ext0",
286*4882a593Smuzhiyun .irq_ack = s3c_irq_ack,
287*4882a593Smuzhiyun .irq_mask = s3c_irq_mask,
288*4882a593Smuzhiyun .irq_unmask = s3c_irq_unmask,
289*4882a593Smuzhiyun .irq_set_wake = s3c_irq_wake,
290*4882a593Smuzhiyun .irq_set_type = s3c_irqext0_type,
291*4882a593Smuzhiyun };
292*4882a593Smuzhiyun
s3c_irq_demux(struct irq_desc * desc)293*4882a593Smuzhiyun static void s3c_irq_demux(struct irq_desc *desc)
294*4882a593Smuzhiyun {
295*4882a593Smuzhiyun struct irq_chip *chip = irq_desc_get_chip(desc);
296*4882a593Smuzhiyun struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc);
297*4882a593Smuzhiyun struct s3c_irq_intc *intc = irq_data->intc;
298*4882a593Smuzhiyun struct s3c_irq_intc *sub_intc = irq_data->sub_intc;
299*4882a593Smuzhiyun unsigned int n, offset, irq;
300*4882a593Smuzhiyun unsigned long src, msk;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun /* we're using individual domains for the non-dt case
303*4882a593Smuzhiyun * and one big domain for the dt case where the subintc
304*4882a593Smuzhiyun * starts at hwirq number 32.
305*4882a593Smuzhiyun */
306*4882a593Smuzhiyun offset = irq_domain_get_of_node(intc->domain) ? 32 : 0;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun chained_irq_enter(chip, desc);
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun src = readl_relaxed(sub_intc->reg_pending);
311*4882a593Smuzhiyun msk = readl_relaxed(sub_intc->reg_mask);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun src &= ~msk;
314*4882a593Smuzhiyun src &= irq_data->sub_bits;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun while (src) {
317*4882a593Smuzhiyun n = __ffs(src);
318*4882a593Smuzhiyun src &= ~(1 << n);
319*4882a593Smuzhiyun irq = irq_find_mapping(sub_intc->domain, offset + n);
320*4882a593Smuzhiyun generic_handle_irq(irq);
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun chained_irq_exit(chip, desc);
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
s3c24xx_handle_intc(struct s3c_irq_intc * intc,struct pt_regs * regs,int intc_offset)326*4882a593Smuzhiyun static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
327*4882a593Smuzhiyun struct pt_regs *regs, int intc_offset)
328*4882a593Smuzhiyun {
329*4882a593Smuzhiyun int pnd;
330*4882a593Smuzhiyun int offset;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun pnd = readl_relaxed(intc->reg_intpnd);
333*4882a593Smuzhiyun if (!pnd)
334*4882a593Smuzhiyun return false;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* non-dt machines use individual domains */
337*4882a593Smuzhiyun if (!irq_domain_get_of_node(intc->domain))
338*4882a593Smuzhiyun intc_offset = 0;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* We have a problem that the INTOFFSET register does not always
341*4882a593Smuzhiyun * show one interrupt. Occasionally we get two interrupts through
342*4882a593Smuzhiyun * the prioritiser, and this causes the INTOFFSET register to show
343*4882a593Smuzhiyun * what looks like the logical-or of the two interrupt numbers.
344*4882a593Smuzhiyun *
345*4882a593Smuzhiyun * Thanks to Klaus, Shannon, et al for helping to debug this problem
346*4882a593Smuzhiyun */
347*4882a593Smuzhiyun offset = readl_relaxed(intc->reg_intpnd + 4);
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* Find the bit manually, when the offset is wrong.
350*4882a593Smuzhiyun * The pending register only ever contains the one bit of the next
351*4882a593Smuzhiyun * interrupt to handle.
352*4882a593Smuzhiyun */
353*4882a593Smuzhiyun if (!(pnd & (1 << offset)))
354*4882a593Smuzhiyun offset = __ffs(pnd);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun handle_domain_irq(intc->domain, intc_offset + offset, regs);
357*4882a593Smuzhiyun return true;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
s3c24xx_handle_irq(struct pt_regs * regs)360*4882a593Smuzhiyun asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun do {
363*4882a593Smuzhiyun /*
364*4882a593Smuzhiyun * For platform based machines, neither ERR nor NULL can happen here.
365*4882a593Smuzhiyun * The s3c24xx_handle_irq() will be set as IRQ handler iff this succeeds:
366*4882a593Smuzhiyun *
367*4882a593Smuzhiyun * s3c_intc[0] = s3c24xx_init_intc()
368*4882a593Smuzhiyun *
369*4882a593Smuzhiyun * If this fails, the next calls to s3c24xx_init_intc() won't be executed.
370*4882a593Smuzhiyun *
371*4882a593Smuzhiyun * For DT machine, s3c_init_intc_of() could set the IRQ handler without
372*4882a593Smuzhiyun * setting s3c_intc[0] only if it was called with num_ctrl=0. There is no
373*4882a593Smuzhiyun * such code path, so again the s3c_intc[0] will have a valid pointer if
374*4882a593Smuzhiyun * set_handle_irq() is called.
375*4882a593Smuzhiyun *
376*4882a593Smuzhiyun * Therefore in s3c24xx_handle_irq(), the s3c_intc[0] is always something.
377*4882a593Smuzhiyun */
378*4882a593Smuzhiyun if (s3c24xx_handle_intc(s3c_intc[0], regs, 0))
379*4882a593Smuzhiyun continue;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun if (!IS_ERR_OR_NULL(s3c_intc[2]))
382*4882a593Smuzhiyun if (s3c24xx_handle_intc(s3c_intc[2], regs, 64))
383*4882a593Smuzhiyun continue;
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun break;
386*4882a593Smuzhiyun } while (1);
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun #ifdef CONFIG_FIQ
390*4882a593Smuzhiyun /**
391*4882a593Smuzhiyun * s3c24xx_set_fiq - set the FIQ routing
392*4882a593Smuzhiyun * @irq: IRQ number to route to FIQ on processor.
393*4882a593Smuzhiyun * @ack_ptr: pointer to a location for storing the bit mask
394*4882a593Smuzhiyun * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing.
395*4882a593Smuzhiyun *
396*4882a593Smuzhiyun * Change the state of the IRQ to FIQ routing depending on @irq and @on. If
397*4882a593Smuzhiyun * @on is true, the @irq is checked to see if it can be routed and the
398*4882a593Smuzhiyun * interrupt controller updated to route the IRQ. If @on is false, the FIQ
399*4882a593Smuzhiyun * routing is cleared, regardless of which @irq is specified.
400*4882a593Smuzhiyun *
401*4882a593Smuzhiyun * returns the mask value for the register.
402*4882a593Smuzhiyun */
s3c24xx_set_fiq(unsigned int irq,u32 * ack_ptr,bool on)403*4882a593Smuzhiyun int s3c24xx_set_fiq(unsigned int irq, u32 *ack_ptr, bool on)
404*4882a593Smuzhiyun {
405*4882a593Smuzhiyun u32 intmod;
406*4882a593Smuzhiyun unsigned offs;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun if (on) {
409*4882a593Smuzhiyun offs = irq - FIQ_START;
410*4882a593Smuzhiyun if (offs > 31)
411*4882a593Smuzhiyun return 0;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun intmod = 1 << offs;
414*4882a593Smuzhiyun } else {
415*4882a593Smuzhiyun intmod = 0;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun if (ack_ptr)
419*4882a593Smuzhiyun *ack_ptr = intmod;
420*4882a593Smuzhiyun writel_relaxed(intmod, S3C2410_INTMOD);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun return intmod;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(s3c24xx_set_fiq);
426*4882a593Smuzhiyun #endif
427*4882a593Smuzhiyun
s3c24xx_irq_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)428*4882a593Smuzhiyun static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq,
429*4882a593Smuzhiyun irq_hw_number_t hw)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun struct s3c_irq_intc *intc = h->host_data;
432*4882a593Smuzhiyun struct s3c_irq_data *irq_data = &intc->irqs[hw];
433*4882a593Smuzhiyun struct s3c_irq_intc *parent_intc;
434*4882a593Smuzhiyun struct s3c_irq_data *parent_irq_data;
435*4882a593Smuzhiyun unsigned int irqno;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* attach controller pointer to irq_data */
438*4882a593Smuzhiyun irq_data->intc = intc;
439*4882a593Smuzhiyun irq_data->offset = hw;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun parent_intc = intc->parent;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun /* set handler and flags */
444*4882a593Smuzhiyun switch (irq_data->type) {
445*4882a593Smuzhiyun case S3C_IRQTYPE_NONE:
446*4882a593Smuzhiyun return 0;
447*4882a593Smuzhiyun case S3C_IRQTYPE_EINT:
448*4882a593Smuzhiyun /* On the S3C2412, the EINT0to3 have a parent irq
449*4882a593Smuzhiyun * but need the s3c_irq_eint0t4 chip
450*4882a593Smuzhiyun */
451*4882a593Smuzhiyun if (parent_intc && (!soc_is_s3c2412() || hw >= 4))
452*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irqext_chip,
453*4882a593Smuzhiyun handle_edge_irq);
454*4882a593Smuzhiyun else
455*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irq_eint0t4,
456*4882a593Smuzhiyun handle_edge_irq);
457*4882a593Smuzhiyun break;
458*4882a593Smuzhiyun case S3C_IRQTYPE_EDGE:
459*4882a593Smuzhiyun if (parent_intc || intc->reg_pending == S3C2416_SRCPND2)
460*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
461*4882a593Smuzhiyun handle_edge_irq);
462*4882a593Smuzhiyun else
463*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irq_chip,
464*4882a593Smuzhiyun handle_edge_irq);
465*4882a593Smuzhiyun break;
466*4882a593Smuzhiyun case S3C_IRQTYPE_LEVEL:
467*4882a593Smuzhiyun if (parent_intc)
468*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
469*4882a593Smuzhiyun handle_level_irq);
470*4882a593Smuzhiyun else
471*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irq_chip,
472*4882a593Smuzhiyun handle_level_irq);
473*4882a593Smuzhiyun break;
474*4882a593Smuzhiyun default:
475*4882a593Smuzhiyun pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type);
476*4882a593Smuzhiyun return -EINVAL;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun irq_set_chip_data(virq, irq_data);
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) {
482*4882a593Smuzhiyun if (irq_data->parent_irq > 31) {
483*4882a593Smuzhiyun pr_err("irq-s3c24xx: parent irq %lu is out of range\n",
484*4882a593Smuzhiyun irq_data->parent_irq);
485*4882a593Smuzhiyun return -EINVAL;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
489*4882a593Smuzhiyun parent_irq_data->sub_intc = intc;
490*4882a593Smuzhiyun parent_irq_data->sub_bits |= (1UL << hw);
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* attach the demuxer to the parent irq */
493*4882a593Smuzhiyun irqno = irq_find_mapping(parent_intc->domain,
494*4882a593Smuzhiyun irq_data->parent_irq);
495*4882a593Smuzhiyun if (!irqno) {
496*4882a593Smuzhiyun pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n",
497*4882a593Smuzhiyun irq_data->parent_irq);
498*4882a593Smuzhiyun return -EINVAL;
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun irq_set_chained_handler(irqno, s3c_irq_demux);
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun return 0;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun static const struct irq_domain_ops s3c24xx_irq_ops = {
507*4882a593Smuzhiyun .map = s3c24xx_irq_map,
508*4882a593Smuzhiyun .xlate = irq_domain_xlate_twocell,
509*4882a593Smuzhiyun };
510*4882a593Smuzhiyun
s3c24xx_clear_intc(struct s3c_irq_intc * intc)511*4882a593Smuzhiyun static void s3c24xx_clear_intc(struct s3c_irq_intc *intc)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun void __iomem *reg_source;
514*4882a593Smuzhiyun unsigned long pend;
515*4882a593Smuzhiyun unsigned long last;
516*4882a593Smuzhiyun int i;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /* if intpnd is set, read the next pending irq from there */
519*4882a593Smuzhiyun reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun last = 0;
522*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
523*4882a593Smuzhiyun pend = readl_relaxed(reg_source);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (pend == 0 || pend == last)
526*4882a593Smuzhiyun break;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun writel_relaxed(pend, intc->reg_pending);
529*4882a593Smuzhiyun if (intc->reg_intpnd)
530*4882a593Smuzhiyun writel_relaxed(pend, intc->reg_intpnd);
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun pr_info("irq: clearing pending status %08x\n", (int)pend);
533*4882a593Smuzhiyun last = pend;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun }
536*4882a593Smuzhiyun
s3c24xx_init_intc(struct device_node * np,struct s3c_irq_data * irq_data,struct s3c_irq_intc * parent,unsigned long address)537*4882a593Smuzhiyun static struct s3c_irq_intc * __init s3c24xx_init_intc(struct device_node *np,
538*4882a593Smuzhiyun struct s3c_irq_data *irq_data,
539*4882a593Smuzhiyun struct s3c_irq_intc *parent,
540*4882a593Smuzhiyun unsigned long address)
541*4882a593Smuzhiyun {
542*4882a593Smuzhiyun struct s3c_irq_intc *intc;
543*4882a593Smuzhiyun void __iomem *base = (void *)0xf6000000; /* static mapping */
544*4882a593Smuzhiyun int irq_num;
545*4882a593Smuzhiyun int irq_start;
546*4882a593Smuzhiyun int ret;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
549*4882a593Smuzhiyun if (!intc)
550*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun intc->irqs = irq_data;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun if (parent)
555*4882a593Smuzhiyun intc->parent = parent;
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun /* select the correct data for the controller.
558*4882a593Smuzhiyun * Need to hard code the irq num start and offset
559*4882a593Smuzhiyun * to preserve the static mapping for now
560*4882a593Smuzhiyun */
561*4882a593Smuzhiyun switch (address) {
562*4882a593Smuzhiyun case 0x4a000000:
563*4882a593Smuzhiyun pr_debug("irq: found main intc\n");
564*4882a593Smuzhiyun intc->reg_pending = base;
565*4882a593Smuzhiyun intc->reg_mask = base + 0x08;
566*4882a593Smuzhiyun intc->reg_intpnd = base + 0x10;
567*4882a593Smuzhiyun irq_num = 32;
568*4882a593Smuzhiyun irq_start = S3C2410_IRQ(0);
569*4882a593Smuzhiyun break;
570*4882a593Smuzhiyun case 0x4a000018:
571*4882a593Smuzhiyun pr_debug("irq: found subintc\n");
572*4882a593Smuzhiyun intc->reg_pending = base + 0x18;
573*4882a593Smuzhiyun intc->reg_mask = base + 0x1c;
574*4882a593Smuzhiyun irq_num = 29;
575*4882a593Smuzhiyun irq_start = S3C2410_IRQSUB(0);
576*4882a593Smuzhiyun break;
577*4882a593Smuzhiyun case 0x4a000040:
578*4882a593Smuzhiyun pr_debug("irq: found intc2\n");
579*4882a593Smuzhiyun intc->reg_pending = base + 0x40;
580*4882a593Smuzhiyun intc->reg_mask = base + 0x48;
581*4882a593Smuzhiyun intc->reg_intpnd = base + 0x50;
582*4882a593Smuzhiyun irq_num = 8;
583*4882a593Smuzhiyun irq_start = S3C2416_IRQ(0);
584*4882a593Smuzhiyun break;
585*4882a593Smuzhiyun case 0x560000a4:
586*4882a593Smuzhiyun pr_debug("irq: found eintc\n");
587*4882a593Smuzhiyun base = (void *)0xfd000000;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun intc->reg_mask = base + 0xa4;
590*4882a593Smuzhiyun intc->reg_pending = base + 0xa8;
591*4882a593Smuzhiyun irq_num = 24;
592*4882a593Smuzhiyun irq_start = S3C2410_IRQ(32);
593*4882a593Smuzhiyun break;
594*4882a593Smuzhiyun default:
595*4882a593Smuzhiyun pr_err("irq: unsupported controller address\n");
596*4882a593Smuzhiyun ret = -EINVAL;
597*4882a593Smuzhiyun goto err;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun /* now that all the data is complete, init the irq-domain */
601*4882a593Smuzhiyun s3c24xx_clear_intc(intc);
602*4882a593Smuzhiyun intc->domain = irq_domain_add_legacy(np, irq_num, irq_start,
603*4882a593Smuzhiyun 0, &s3c24xx_irq_ops,
604*4882a593Smuzhiyun intc);
605*4882a593Smuzhiyun if (!intc->domain) {
606*4882a593Smuzhiyun pr_err("irq: could not create irq-domain\n");
607*4882a593Smuzhiyun ret = -EINVAL;
608*4882a593Smuzhiyun goto err;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun set_handle_irq(s3c24xx_handle_irq);
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun return intc;
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun err:
616*4882a593Smuzhiyun kfree(intc);
617*4882a593Smuzhiyun return ERR_PTR(ret);
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun static struct s3c_irq_data __maybe_unused init_eint[32] = {
621*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
622*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
623*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
624*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
625*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
626*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
627*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
628*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
629*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
630*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
631*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
632*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
633*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
634*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
635*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
636*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
637*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
638*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
639*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
640*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
641*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
642*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
643*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
644*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
645*4882a593Smuzhiyun };
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun #ifdef CONFIG_CPU_S3C2410
648*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2410base[32] = {
649*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
650*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
651*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
652*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
653*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
654*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
655*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
656*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
657*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
658*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
659*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
660*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
661*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
662*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
663*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
664*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
665*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
666*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
667*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
668*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
669*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
670*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
671*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
672*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
673*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
674*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
675*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
676*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
677*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
678*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
679*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
680*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
681*4882a593Smuzhiyun };
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2410subint[32] = {
684*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
685*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
686*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
687*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
688*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
689*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
690*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
691*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
692*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
693*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
694*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
695*4882a593Smuzhiyun };
696*4882a593Smuzhiyun
s3c2410_init_irq(void)697*4882a593Smuzhiyun void __init s3c2410_init_irq(void)
698*4882a593Smuzhiyun {
699*4882a593Smuzhiyun #ifdef CONFIG_FIQ
700*4882a593Smuzhiyun init_FIQ(FIQ_START);
701*4882a593Smuzhiyun #endif
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL,
704*4882a593Smuzhiyun 0x4a000000);
705*4882a593Smuzhiyun if (IS_ERR(s3c_intc[0])) {
706*4882a593Smuzhiyun pr_err("irq: could not create main interrupt controller\n");
707*4882a593Smuzhiyun return;
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0],
711*4882a593Smuzhiyun s3c_intc[0], 0x4a000018);
712*4882a593Smuzhiyun s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun #endif
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun #ifdef CONFIG_CPU_S3C2412
717*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2412base[32] = {
718*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT0 */
719*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT1 */
720*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT2 */
721*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT3 */
722*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
723*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
724*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
725*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
726*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
727*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
728*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
729*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
730*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
731*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
732*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
733*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
734*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
735*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
736*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
737*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
738*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
739*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* SDI/CF */
740*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
741*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
742*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
743*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
744*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
745*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
746*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
747*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
748*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
749*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
750*4882a593Smuzhiyun };
751*4882a593Smuzhiyun
752*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2412eint[32] = {
753*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 0 }, /* EINT0 */
754*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 1 }, /* EINT1 */
755*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 2 }, /* EINT2 */
756*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 3 }, /* EINT3 */
757*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */
758*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */
759*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */
760*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */
761*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */
762*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */
763*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */
764*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */
765*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */
766*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */
767*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */
768*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */
769*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */
770*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */
771*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */
772*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */
773*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */
774*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */
775*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */
776*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */
777*4882a593Smuzhiyun };
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2412subint[32] = {
780*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
781*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
782*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
783*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
784*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
785*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
786*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
787*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
788*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
789*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
790*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
791*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, },
792*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, },
793*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* SDI */
794*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* CF */
795*4882a593Smuzhiyun };
796*4882a593Smuzhiyun
s3c2412_init_irq(void)797*4882a593Smuzhiyun void __init s3c2412_init_irq(void)
798*4882a593Smuzhiyun {
799*4882a593Smuzhiyun pr_info("S3C2412: IRQ Support\n");
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun #ifdef CONFIG_FIQ
802*4882a593Smuzhiyun init_FIQ(FIQ_START);
803*4882a593Smuzhiyun #endif
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL,
806*4882a593Smuzhiyun 0x4a000000);
807*4882a593Smuzhiyun if (IS_ERR(s3c_intc[0])) {
808*4882a593Smuzhiyun pr_err("irq: could not create main interrupt controller\n");
809*4882a593Smuzhiyun return;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4);
813*4882a593Smuzhiyun s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0],
814*4882a593Smuzhiyun s3c_intc[0], 0x4a000018);
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun #endif
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun #ifdef CONFIG_CPU_S3C2416
819*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2416base[32] = {
820*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
821*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
822*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
823*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
824*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
825*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
826*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
827*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
828*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
829*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
830*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
831*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
832*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
833*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
834*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
835*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
836*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
837*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
838*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
839*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, }, /* reserved */
840*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
841*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
842*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
843*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
844*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
845*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
846*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
847*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
848*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
849*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE, },
850*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
851*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
852*4882a593Smuzhiyun };
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2416subint[32] = {
855*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
856*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
857*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
858*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
859*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
860*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
861*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
862*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
863*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
864*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
865*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
866*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
867*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
868*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
869*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
870*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
871*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
872*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
873*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
874*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
875*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
876*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
877*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
878*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
879*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
880*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
881*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
882*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
883*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
884*4882a593Smuzhiyun };
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2416_second[32] = {
887*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE }, /* 2D */
888*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
889*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
890*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
891*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */
892*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
893*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */
894*4882a593Smuzhiyun };
895*4882a593Smuzhiyun
s3c2416_init_irq(void)896*4882a593Smuzhiyun void __init s3c2416_init_irq(void)
897*4882a593Smuzhiyun {
898*4882a593Smuzhiyun pr_info("S3C2416: IRQ Support\n");
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun #ifdef CONFIG_FIQ
901*4882a593Smuzhiyun init_FIQ(FIQ_START);
902*4882a593Smuzhiyun #endif
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL,
905*4882a593Smuzhiyun 0x4a000000);
906*4882a593Smuzhiyun if (IS_ERR(s3c_intc[0])) {
907*4882a593Smuzhiyun pr_err("irq: could not create main interrupt controller\n");
908*4882a593Smuzhiyun return;
909*4882a593Smuzhiyun }
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
912*4882a593Smuzhiyun s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0],
913*4882a593Smuzhiyun s3c_intc[0], 0x4a000018);
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0],
916*4882a593Smuzhiyun NULL, 0x4a000040);
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun #endif
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun #ifdef CONFIG_CPU_S3C2440
922*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2440base[32] = {
923*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
924*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
925*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
926*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
927*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
928*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
929*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
930*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
931*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
932*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
933*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
934*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
935*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
936*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
937*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
938*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
939*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
940*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
941*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
942*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
943*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
944*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
945*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
946*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
947*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */
948*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
949*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
950*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
951*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
952*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
953*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
954*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
955*4882a593Smuzhiyun };
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2440subint[32] = {
958*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
959*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
960*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
961*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
962*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
963*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
964*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
965*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
966*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
967*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
968*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
969*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
970*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
971*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
972*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
973*4882a593Smuzhiyun };
974*4882a593Smuzhiyun
s3c2440_init_irq(void)975*4882a593Smuzhiyun void __init s3c2440_init_irq(void)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun pr_info("S3C2440: IRQ Support\n");
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun #ifdef CONFIG_FIQ
980*4882a593Smuzhiyun init_FIQ(FIQ_START);
981*4882a593Smuzhiyun #endif
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL,
984*4882a593Smuzhiyun 0x4a000000);
985*4882a593Smuzhiyun if (IS_ERR(s3c_intc[0])) {
986*4882a593Smuzhiyun pr_err("irq: could not create main interrupt controller\n");
987*4882a593Smuzhiyun return;
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
991*4882a593Smuzhiyun s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0],
992*4882a593Smuzhiyun s3c_intc[0], 0x4a000018);
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun #endif
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun #ifdef CONFIG_CPU_S3C2442
997*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2442base[32] = {
998*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
999*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
1000*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
1001*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
1002*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
1003*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
1004*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
1005*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
1006*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
1007*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* WDT */
1008*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
1009*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
1010*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
1011*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
1012*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
1013*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
1014*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* LCD */
1015*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */
1016*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */
1017*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */
1018*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */
1019*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SDI */
1020*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
1021*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
1022*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */
1023*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
1024*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
1025*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
1026*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
1027*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
1028*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
1029*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
1030*4882a593Smuzhiyun };
1031*4882a593Smuzhiyun
1032*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2442subint[32] = {
1033*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
1034*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
1035*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
1036*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
1037*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
1038*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
1039*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
1040*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
1041*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
1042*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
1043*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
1044*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
1045*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
1046*4882a593Smuzhiyun };
1047*4882a593Smuzhiyun
s3c2442_init_irq(void)1048*4882a593Smuzhiyun void __init s3c2442_init_irq(void)
1049*4882a593Smuzhiyun {
1050*4882a593Smuzhiyun pr_info("S3C2442: IRQ Support\n");
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun #ifdef CONFIG_FIQ
1053*4882a593Smuzhiyun init_FIQ(FIQ_START);
1054*4882a593Smuzhiyun #endif
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL,
1057*4882a593Smuzhiyun 0x4a000000);
1058*4882a593Smuzhiyun if (IS_ERR(s3c_intc[0])) {
1059*4882a593Smuzhiyun pr_err("irq: could not create main interrupt controller\n");
1060*4882a593Smuzhiyun return;
1061*4882a593Smuzhiyun }
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
1064*4882a593Smuzhiyun s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0],
1065*4882a593Smuzhiyun s3c_intc[0], 0x4a000018);
1066*4882a593Smuzhiyun }
1067*4882a593Smuzhiyun #endif
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun #ifdef CONFIG_CPU_S3C2443
1070*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2443base[32] = {
1071*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */
1072*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */
1073*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */
1074*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */
1075*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */
1076*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */
1077*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */
1078*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */
1079*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TICK */
1080*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */
1081*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */
1082*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */
1083*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */
1084*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */
1085*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */
1086*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */
1087*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */
1088*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */
1089*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */
1090*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* CFON */
1091*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */
1092*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */
1093*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */
1094*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */
1095*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* NAND */
1096*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBD */
1097*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* USBH */
1098*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* IIC */
1099*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */
1100*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */
1101*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, }, /* RTC */
1102*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */
1103*4882a593Smuzhiyun };
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun
1106*4882a593Smuzhiyun static struct s3c_irq_data init_s3c2443subint[32] = {
1107*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */
1108*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */
1109*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */
1110*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */
1111*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */
1112*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */
1113*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */
1114*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */
1115*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */
1116*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */
1117*4882a593Smuzhiyun { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */
1118*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */
1119*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */
1120*4882a593Smuzhiyun { .type = S3C_IRQTYPE_NONE }, /* reserved */
1121*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */
1122*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */
1123*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */
1124*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */
1125*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */
1126*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */
1127*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */
1128*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */
1129*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */
1130*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */
1131*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */
1132*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */
1133*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */
1134*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */
1135*4882a593Smuzhiyun { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */
1136*4882a593Smuzhiyun };
1137*4882a593Smuzhiyun
s3c2443_init_irq(void)1138*4882a593Smuzhiyun void __init s3c2443_init_irq(void)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun pr_info("S3C2443: IRQ Support\n");
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun #ifdef CONFIG_FIQ
1143*4882a593Smuzhiyun init_FIQ(FIQ_START);
1144*4882a593Smuzhiyun #endif
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL,
1147*4882a593Smuzhiyun 0x4a000000);
1148*4882a593Smuzhiyun if (IS_ERR(s3c_intc[0])) {
1149*4882a593Smuzhiyun pr_err("irq: could not create main interrupt controller\n");
1150*4882a593Smuzhiyun return;
1151*4882a593Smuzhiyun }
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4);
1154*4882a593Smuzhiyun s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0],
1155*4882a593Smuzhiyun s3c_intc[0], 0x4a000018);
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun #endif
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun #ifdef CONFIG_OF
s3c24xx_irq_map_of(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)1160*4882a593Smuzhiyun static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq,
1161*4882a593Smuzhiyun irq_hw_number_t hw)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun unsigned int ctrl_num = hw / 32;
1164*4882a593Smuzhiyun unsigned int intc_hw = hw % 32;
1165*4882a593Smuzhiyun struct s3c_irq_intc *intc = s3c_intc[ctrl_num];
1166*4882a593Smuzhiyun struct s3c_irq_intc *parent_intc = intc->parent;
1167*4882a593Smuzhiyun struct s3c_irq_data *irq_data = &intc->irqs[intc_hw];
1168*4882a593Smuzhiyun
1169*4882a593Smuzhiyun /* attach controller pointer to irq_data */
1170*4882a593Smuzhiyun irq_data->intc = intc;
1171*4882a593Smuzhiyun irq_data->offset = intc_hw;
1172*4882a593Smuzhiyun
1173*4882a593Smuzhiyun if (!parent_intc)
1174*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq);
1175*4882a593Smuzhiyun else
1176*4882a593Smuzhiyun irq_set_chip_and_handler(virq, &s3c_irq_level_chip,
1177*4882a593Smuzhiyun handle_edge_irq);
1178*4882a593Smuzhiyun
1179*4882a593Smuzhiyun irq_set_chip_data(virq, irq_data);
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun return 0;
1182*4882a593Smuzhiyun }
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun /* Translate our of irq notation
1185*4882a593Smuzhiyun * format: <ctrl_num ctrl_irq parent_irq type>
1186*4882a593Smuzhiyun */
s3c24xx_irq_xlate_of(struct irq_domain * d,struct device_node * n,const u32 * intspec,unsigned int intsize,irq_hw_number_t * out_hwirq,unsigned int * out_type)1187*4882a593Smuzhiyun static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n,
1188*4882a593Smuzhiyun const u32 *intspec, unsigned int intsize,
1189*4882a593Smuzhiyun irq_hw_number_t *out_hwirq, unsigned int *out_type)
1190*4882a593Smuzhiyun {
1191*4882a593Smuzhiyun struct s3c_irq_intc *intc;
1192*4882a593Smuzhiyun struct s3c_irq_intc *parent_intc;
1193*4882a593Smuzhiyun struct s3c_irq_data *irq_data;
1194*4882a593Smuzhiyun struct s3c_irq_data *parent_irq_data;
1195*4882a593Smuzhiyun int irqno;
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun if (WARN_ON(intsize < 4))
1198*4882a593Smuzhiyun return -EINVAL;
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun if (intspec[0] > 2 || !s3c_intc[intspec[0]]) {
1201*4882a593Smuzhiyun pr_err("controller number %d invalid\n", intspec[0]);
1202*4882a593Smuzhiyun return -EINVAL;
1203*4882a593Smuzhiyun }
1204*4882a593Smuzhiyun intc = s3c_intc[intspec[0]];
1205*4882a593Smuzhiyun
1206*4882a593Smuzhiyun *out_hwirq = intspec[0] * 32 + intspec[2];
1207*4882a593Smuzhiyun *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun parent_intc = intc->parent;
1210*4882a593Smuzhiyun if (parent_intc) {
1211*4882a593Smuzhiyun irq_data = &intc->irqs[intspec[2]];
1212*4882a593Smuzhiyun irq_data->parent_irq = intspec[1];
1213*4882a593Smuzhiyun parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];
1214*4882a593Smuzhiyun parent_irq_data->sub_intc = intc;
1215*4882a593Smuzhiyun parent_irq_data->sub_bits |= (1UL << intspec[2]);
1216*4882a593Smuzhiyun
1217*4882a593Smuzhiyun /* parent_intc is always s3c_intc[0], so no offset */
1218*4882a593Smuzhiyun irqno = irq_create_mapping(parent_intc->domain, intspec[1]);
1219*4882a593Smuzhiyun if (irqno < 0) {
1220*4882a593Smuzhiyun pr_err("irq: could not map parent interrupt\n");
1221*4882a593Smuzhiyun return irqno;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun irq_set_chained_handler(irqno, s3c_irq_demux);
1225*4882a593Smuzhiyun }
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun return 0;
1228*4882a593Smuzhiyun }
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun static const struct irq_domain_ops s3c24xx_irq_ops_of = {
1231*4882a593Smuzhiyun .map = s3c24xx_irq_map_of,
1232*4882a593Smuzhiyun .xlate = s3c24xx_irq_xlate_of,
1233*4882a593Smuzhiyun };
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun struct s3c24xx_irq_of_ctrl {
1236*4882a593Smuzhiyun char *name;
1237*4882a593Smuzhiyun unsigned long offset;
1238*4882a593Smuzhiyun struct s3c_irq_intc **handle;
1239*4882a593Smuzhiyun struct s3c_irq_intc **parent;
1240*4882a593Smuzhiyun struct irq_domain_ops *ops;
1241*4882a593Smuzhiyun };
1242*4882a593Smuzhiyun
s3c_init_intc_of(struct device_node * np,struct device_node * interrupt_parent,struct s3c24xx_irq_of_ctrl * s3c_ctrl,int num_ctrl)1243*4882a593Smuzhiyun static int __init s3c_init_intc_of(struct device_node *np,
1244*4882a593Smuzhiyun struct device_node *interrupt_parent,
1245*4882a593Smuzhiyun struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl)
1246*4882a593Smuzhiyun {
1247*4882a593Smuzhiyun struct s3c_irq_intc *intc;
1248*4882a593Smuzhiyun struct s3c24xx_irq_of_ctrl *ctrl;
1249*4882a593Smuzhiyun struct irq_domain *domain;
1250*4882a593Smuzhiyun void __iomem *reg_base;
1251*4882a593Smuzhiyun int i;
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun reg_base = of_iomap(np, 0);
1254*4882a593Smuzhiyun if (!reg_base) {
1255*4882a593Smuzhiyun pr_err("irq-s3c24xx: could not map irq registers\n");
1256*4882a593Smuzhiyun return -EINVAL;
1257*4882a593Smuzhiyun }
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun domain = irq_domain_add_linear(np, num_ctrl * 32,
1260*4882a593Smuzhiyun &s3c24xx_irq_ops_of, NULL);
1261*4882a593Smuzhiyun if (!domain) {
1262*4882a593Smuzhiyun pr_err("irq: could not create irq-domain\n");
1263*4882a593Smuzhiyun return -EINVAL;
1264*4882a593Smuzhiyun }
1265*4882a593Smuzhiyun
1266*4882a593Smuzhiyun for (i = 0; i < num_ctrl; i++) {
1267*4882a593Smuzhiyun ctrl = &s3c_ctrl[i];
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun pr_debug("irq: found controller %s\n", ctrl->name);
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);
1272*4882a593Smuzhiyun if (!intc)
1273*4882a593Smuzhiyun return -ENOMEM;
1274*4882a593Smuzhiyun
1275*4882a593Smuzhiyun intc->domain = domain;
1276*4882a593Smuzhiyun intc->irqs = kcalloc(32, sizeof(struct s3c_irq_data),
1277*4882a593Smuzhiyun GFP_KERNEL);
1278*4882a593Smuzhiyun if (!intc->irqs) {
1279*4882a593Smuzhiyun kfree(intc);
1280*4882a593Smuzhiyun return -ENOMEM;
1281*4882a593Smuzhiyun }
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun if (ctrl->parent) {
1284*4882a593Smuzhiyun intc->reg_pending = reg_base + ctrl->offset;
1285*4882a593Smuzhiyun intc->reg_mask = reg_base + ctrl->offset + 0x4;
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun if (*(ctrl->parent)) {
1288*4882a593Smuzhiyun intc->parent = *(ctrl->parent);
1289*4882a593Smuzhiyun } else {
1290*4882a593Smuzhiyun pr_warn("irq: parent of %s missing\n",
1291*4882a593Smuzhiyun ctrl->name);
1292*4882a593Smuzhiyun kfree(intc->irqs);
1293*4882a593Smuzhiyun kfree(intc);
1294*4882a593Smuzhiyun continue;
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun } else {
1297*4882a593Smuzhiyun intc->reg_pending = reg_base + ctrl->offset;
1298*4882a593Smuzhiyun intc->reg_mask = reg_base + ctrl->offset + 0x08;
1299*4882a593Smuzhiyun intc->reg_intpnd = reg_base + ctrl->offset + 0x10;
1300*4882a593Smuzhiyun }
1301*4882a593Smuzhiyun
1302*4882a593Smuzhiyun s3c24xx_clear_intc(intc);
1303*4882a593Smuzhiyun s3c_intc[i] = intc;
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun set_handle_irq(s3c24xx_handle_irq);
1307*4882a593Smuzhiyun
1308*4882a593Smuzhiyun return 0;
1309*4882a593Smuzhiyun }
1310*4882a593Smuzhiyun
1311*4882a593Smuzhiyun static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
1312*4882a593Smuzhiyun {
1313*4882a593Smuzhiyun .name = "intc",
1314*4882a593Smuzhiyun .offset = 0,
1315*4882a593Smuzhiyun }, {
1316*4882a593Smuzhiyun .name = "subintc",
1317*4882a593Smuzhiyun .offset = 0x18,
1318*4882a593Smuzhiyun .parent = &s3c_intc[0],
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun };
1321*4882a593Smuzhiyun
s3c2410_init_intc_of(struct device_node * np,struct device_node * interrupt_parent)1322*4882a593Smuzhiyun int __init s3c2410_init_intc_of(struct device_node *np,
1323*4882a593Smuzhiyun struct device_node *interrupt_parent)
1324*4882a593Smuzhiyun {
1325*4882a593Smuzhiyun return s3c_init_intc_of(np, interrupt_parent,
1326*4882a593Smuzhiyun s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
1327*4882a593Smuzhiyun }
1328*4882a593Smuzhiyun IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = {
1331*4882a593Smuzhiyun {
1332*4882a593Smuzhiyun .name = "intc",
1333*4882a593Smuzhiyun .offset = 0,
1334*4882a593Smuzhiyun }, {
1335*4882a593Smuzhiyun .name = "subintc",
1336*4882a593Smuzhiyun .offset = 0x18,
1337*4882a593Smuzhiyun .parent = &s3c_intc[0],
1338*4882a593Smuzhiyun }, {
1339*4882a593Smuzhiyun .name = "intc2",
1340*4882a593Smuzhiyun .offset = 0x40,
1341*4882a593Smuzhiyun }
1342*4882a593Smuzhiyun };
1343*4882a593Smuzhiyun
s3c2416_init_intc_of(struct device_node * np,struct device_node * interrupt_parent)1344*4882a593Smuzhiyun int __init s3c2416_init_intc_of(struct device_node *np,
1345*4882a593Smuzhiyun struct device_node *interrupt_parent)
1346*4882a593Smuzhiyun {
1347*4882a593Smuzhiyun return s3c_init_intc_of(np, interrupt_parent,
1348*4882a593Smuzhiyun s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl));
1349*4882a593Smuzhiyun }
1350*4882a593Smuzhiyun IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of);
1351*4882a593Smuzhiyun #endif
1352