1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * arch/powerpc/sysdev/qe_lib/qe_ic.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2006 Freescale Semiconductor, Inc. All rights reserved.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Author: Li Yang <leoli@freescale.com>
8*4882a593Smuzhiyun * Based on code from Shlomi Gridish <gridish@freescale.com>
9*4882a593Smuzhiyun *
10*4882a593Smuzhiyun * QUICC ENGINE Interrupt Controller
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/of_irq.h>
14*4882a593Smuzhiyun #include <linux/of_address.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/init.h>
17*4882a593Smuzhiyun #include <linux/errno.h>
18*4882a593Smuzhiyun #include <linux/irq.h>
19*4882a593Smuzhiyun #include <linux/reboot.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun #include <linux/stddef.h>
22*4882a593Smuzhiyun #include <linux/sched.h>
23*4882a593Smuzhiyun #include <linux/signal.h>
24*4882a593Smuzhiyun #include <linux/device.h>
25*4882a593Smuzhiyun #include <linux/spinlock.h>
26*4882a593Smuzhiyun #include <asm/irq.h>
27*4882a593Smuzhiyun #include <asm/io.h>
28*4882a593Smuzhiyun #include <soc/fsl/qe/qe.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define NR_QE_IC_INTS 64
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun /* QE IC registers offset */
33*4882a593Smuzhiyun #define QEIC_CICR 0x00
34*4882a593Smuzhiyun #define QEIC_CIVEC 0x04
35*4882a593Smuzhiyun #define QEIC_CIPXCC 0x10
36*4882a593Smuzhiyun #define QEIC_CIPYCC 0x14
37*4882a593Smuzhiyun #define QEIC_CIPWCC 0x18
38*4882a593Smuzhiyun #define QEIC_CIPZCC 0x1c
39*4882a593Smuzhiyun #define QEIC_CIMR 0x20
40*4882a593Smuzhiyun #define QEIC_CRIMR 0x24
41*4882a593Smuzhiyun #define QEIC_CIPRTA 0x30
42*4882a593Smuzhiyun #define QEIC_CIPRTB 0x34
43*4882a593Smuzhiyun #define QEIC_CHIVEC 0x60
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun struct qe_ic {
46*4882a593Smuzhiyun /* Control registers offset */
47*4882a593Smuzhiyun __be32 __iomem *regs;
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun /* The remapper for this QEIC */
50*4882a593Smuzhiyun struct irq_domain *irqhost;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun /* The "linux" controller struct */
53*4882a593Smuzhiyun struct irq_chip hc_irq;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /* VIRQ numbers of QE high/low irqs */
56*4882a593Smuzhiyun unsigned int virq_high;
57*4882a593Smuzhiyun unsigned int virq_low;
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /*
61*4882a593Smuzhiyun * QE interrupt controller internal structure
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun struct qe_ic_info {
64*4882a593Smuzhiyun /* Location of this source at the QIMR register */
65*4882a593Smuzhiyun u32 mask;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* Mask register offset */
68*4882a593Smuzhiyun u32 mask_reg;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * For grouped interrupts sources - the interrupt code as
72*4882a593Smuzhiyun * appears at the group priority register
73*4882a593Smuzhiyun */
74*4882a593Smuzhiyun u8 pri_code;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun /* Group priority register offset */
77*4882a593Smuzhiyun u32 pri_reg;
78*4882a593Smuzhiyun };
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun static DEFINE_RAW_SPINLOCK(qe_ic_lock);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun static struct qe_ic_info qe_ic_info[] = {
83*4882a593Smuzhiyun [1] = {
84*4882a593Smuzhiyun .mask = 0x00008000,
85*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
86*4882a593Smuzhiyun .pri_code = 0,
87*4882a593Smuzhiyun .pri_reg = QEIC_CIPWCC,
88*4882a593Smuzhiyun },
89*4882a593Smuzhiyun [2] = {
90*4882a593Smuzhiyun .mask = 0x00004000,
91*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
92*4882a593Smuzhiyun .pri_code = 1,
93*4882a593Smuzhiyun .pri_reg = QEIC_CIPWCC,
94*4882a593Smuzhiyun },
95*4882a593Smuzhiyun [3] = {
96*4882a593Smuzhiyun .mask = 0x00002000,
97*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
98*4882a593Smuzhiyun .pri_code = 2,
99*4882a593Smuzhiyun .pri_reg = QEIC_CIPWCC,
100*4882a593Smuzhiyun },
101*4882a593Smuzhiyun [10] = {
102*4882a593Smuzhiyun .mask = 0x00000040,
103*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
104*4882a593Smuzhiyun .pri_code = 1,
105*4882a593Smuzhiyun .pri_reg = QEIC_CIPZCC,
106*4882a593Smuzhiyun },
107*4882a593Smuzhiyun [11] = {
108*4882a593Smuzhiyun .mask = 0x00000020,
109*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
110*4882a593Smuzhiyun .pri_code = 2,
111*4882a593Smuzhiyun .pri_reg = QEIC_CIPZCC,
112*4882a593Smuzhiyun },
113*4882a593Smuzhiyun [12] = {
114*4882a593Smuzhiyun .mask = 0x00000010,
115*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
116*4882a593Smuzhiyun .pri_code = 3,
117*4882a593Smuzhiyun .pri_reg = QEIC_CIPZCC,
118*4882a593Smuzhiyun },
119*4882a593Smuzhiyun [13] = {
120*4882a593Smuzhiyun .mask = 0x00000008,
121*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
122*4882a593Smuzhiyun .pri_code = 4,
123*4882a593Smuzhiyun .pri_reg = QEIC_CIPZCC,
124*4882a593Smuzhiyun },
125*4882a593Smuzhiyun [14] = {
126*4882a593Smuzhiyun .mask = 0x00000004,
127*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
128*4882a593Smuzhiyun .pri_code = 5,
129*4882a593Smuzhiyun .pri_reg = QEIC_CIPZCC,
130*4882a593Smuzhiyun },
131*4882a593Smuzhiyun [15] = {
132*4882a593Smuzhiyun .mask = 0x00000002,
133*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
134*4882a593Smuzhiyun .pri_code = 6,
135*4882a593Smuzhiyun .pri_reg = QEIC_CIPZCC,
136*4882a593Smuzhiyun },
137*4882a593Smuzhiyun [20] = {
138*4882a593Smuzhiyun .mask = 0x10000000,
139*4882a593Smuzhiyun .mask_reg = QEIC_CRIMR,
140*4882a593Smuzhiyun .pri_code = 3,
141*4882a593Smuzhiyun .pri_reg = QEIC_CIPRTA,
142*4882a593Smuzhiyun },
143*4882a593Smuzhiyun [25] = {
144*4882a593Smuzhiyun .mask = 0x00800000,
145*4882a593Smuzhiyun .mask_reg = QEIC_CRIMR,
146*4882a593Smuzhiyun .pri_code = 0,
147*4882a593Smuzhiyun .pri_reg = QEIC_CIPRTB,
148*4882a593Smuzhiyun },
149*4882a593Smuzhiyun [26] = {
150*4882a593Smuzhiyun .mask = 0x00400000,
151*4882a593Smuzhiyun .mask_reg = QEIC_CRIMR,
152*4882a593Smuzhiyun .pri_code = 1,
153*4882a593Smuzhiyun .pri_reg = QEIC_CIPRTB,
154*4882a593Smuzhiyun },
155*4882a593Smuzhiyun [27] = {
156*4882a593Smuzhiyun .mask = 0x00200000,
157*4882a593Smuzhiyun .mask_reg = QEIC_CRIMR,
158*4882a593Smuzhiyun .pri_code = 2,
159*4882a593Smuzhiyun .pri_reg = QEIC_CIPRTB,
160*4882a593Smuzhiyun },
161*4882a593Smuzhiyun [28] = {
162*4882a593Smuzhiyun .mask = 0x00100000,
163*4882a593Smuzhiyun .mask_reg = QEIC_CRIMR,
164*4882a593Smuzhiyun .pri_code = 3,
165*4882a593Smuzhiyun .pri_reg = QEIC_CIPRTB,
166*4882a593Smuzhiyun },
167*4882a593Smuzhiyun [32] = {
168*4882a593Smuzhiyun .mask = 0x80000000,
169*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
170*4882a593Smuzhiyun .pri_code = 0,
171*4882a593Smuzhiyun .pri_reg = QEIC_CIPXCC,
172*4882a593Smuzhiyun },
173*4882a593Smuzhiyun [33] = {
174*4882a593Smuzhiyun .mask = 0x40000000,
175*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
176*4882a593Smuzhiyun .pri_code = 1,
177*4882a593Smuzhiyun .pri_reg = QEIC_CIPXCC,
178*4882a593Smuzhiyun },
179*4882a593Smuzhiyun [34] = {
180*4882a593Smuzhiyun .mask = 0x20000000,
181*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
182*4882a593Smuzhiyun .pri_code = 2,
183*4882a593Smuzhiyun .pri_reg = QEIC_CIPXCC,
184*4882a593Smuzhiyun },
185*4882a593Smuzhiyun [35] = {
186*4882a593Smuzhiyun .mask = 0x10000000,
187*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
188*4882a593Smuzhiyun .pri_code = 3,
189*4882a593Smuzhiyun .pri_reg = QEIC_CIPXCC,
190*4882a593Smuzhiyun },
191*4882a593Smuzhiyun [36] = {
192*4882a593Smuzhiyun .mask = 0x08000000,
193*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
194*4882a593Smuzhiyun .pri_code = 4,
195*4882a593Smuzhiyun .pri_reg = QEIC_CIPXCC,
196*4882a593Smuzhiyun },
197*4882a593Smuzhiyun [40] = {
198*4882a593Smuzhiyun .mask = 0x00800000,
199*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
200*4882a593Smuzhiyun .pri_code = 0,
201*4882a593Smuzhiyun .pri_reg = QEIC_CIPYCC,
202*4882a593Smuzhiyun },
203*4882a593Smuzhiyun [41] = {
204*4882a593Smuzhiyun .mask = 0x00400000,
205*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
206*4882a593Smuzhiyun .pri_code = 1,
207*4882a593Smuzhiyun .pri_reg = QEIC_CIPYCC,
208*4882a593Smuzhiyun },
209*4882a593Smuzhiyun [42] = {
210*4882a593Smuzhiyun .mask = 0x00200000,
211*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
212*4882a593Smuzhiyun .pri_code = 2,
213*4882a593Smuzhiyun .pri_reg = QEIC_CIPYCC,
214*4882a593Smuzhiyun },
215*4882a593Smuzhiyun [43] = {
216*4882a593Smuzhiyun .mask = 0x00100000,
217*4882a593Smuzhiyun .mask_reg = QEIC_CIMR,
218*4882a593Smuzhiyun .pri_code = 3,
219*4882a593Smuzhiyun .pri_reg = QEIC_CIPYCC,
220*4882a593Smuzhiyun },
221*4882a593Smuzhiyun };
222*4882a593Smuzhiyun
qe_ic_read(__be32 __iomem * base,unsigned int reg)223*4882a593Smuzhiyun static inline u32 qe_ic_read(__be32 __iomem *base, unsigned int reg)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun return qe_ioread32be(base + (reg >> 2));
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
qe_ic_write(__be32 __iomem * base,unsigned int reg,u32 value)228*4882a593Smuzhiyun static inline void qe_ic_write(__be32 __iomem *base, unsigned int reg,
229*4882a593Smuzhiyun u32 value)
230*4882a593Smuzhiyun {
231*4882a593Smuzhiyun qe_iowrite32be(value, base + (reg >> 2));
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
qe_ic_from_irq(unsigned int virq)234*4882a593Smuzhiyun static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun return irq_get_chip_data(virq);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
qe_ic_from_irq_data(struct irq_data * d)239*4882a593Smuzhiyun static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun return irq_data_get_irq_chip_data(d);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
qe_ic_unmask_irq(struct irq_data * d)244*4882a593Smuzhiyun static void qe_ic_unmask_irq(struct irq_data *d)
245*4882a593Smuzhiyun {
246*4882a593Smuzhiyun struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
247*4882a593Smuzhiyun unsigned int src = irqd_to_hwirq(d);
248*4882a593Smuzhiyun unsigned long flags;
249*4882a593Smuzhiyun u32 temp;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun raw_spin_lock_irqsave(&qe_ic_lock, flags);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
254*4882a593Smuzhiyun qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
255*4882a593Smuzhiyun temp | qe_ic_info[src].mask);
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
qe_ic_mask_irq(struct irq_data * d)260*4882a593Smuzhiyun static void qe_ic_mask_irq(struct irq_data *d)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
263*4882a593Smuzhiyun unsigned int src = irqd_to_hwirq(d);
264*4882a593Smuzhiyun unsigned long flags;
265*4882a593Smuzhiyun u32 temp;
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun raw_spin_lock_irqsave(&qe_ic_lock, flags);
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
270*4882a593Smuzhiyun qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
271*4882a593Smuzhiyun temp & ~qe_ic_info[src].mask);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* Flush the above write before enabling interrupts; otherwise,
274*4882a593Smuzhiyun * spurious interrupts will sometimes happen. To be 100% sure
275*4882a593Smuzhiyun * that the write has reached the device before interrupts are
276*4882a593Smuzhiyun * enabled, the mask register would have to be read back; however,
277*4882a593Smuzhiyun * this is not required for correctness, only to avoid wasting
278*4882a593Smuzhiyun * time on a large number of spurious interrupts. In testing,
279*4882a593Smuzhiyun * a sync reduced the observed spurious interrupts to zero.
280*4882a593Smuzhiyun */
281*4882a593Smuzhiyun mb();
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun raw_spin_unlock_irqrestore(&qe_ic_lock, flags);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun static struct irq_chip qe_ic_irq_chip = {
287*4882a593Smuzhiyun .name = "QEIC",
288*4882a593Smuzhiyun .irq_unmask = qe_ic_unmask_irq,
289*4882a593Smuzhiyun .irq_mask = qe_ic_mask_irq,
290*4882a593Smuzhiyun .irq_mask_ack = qe_ic_mask_irq,
291*4882a593Smuzhiyun };
292*4882a593Smuzhiyun
qe_ic_host_match(struct irq_domain * h,struct device_node * node,enum irq_domain_bus_token bus_token)293*4882a593Smuzhiyun static int qe_ic_host_match(struct irq_domain *h, struct device_node *node,
294*4882a593Smuzhiyun enum irq_domain_bus_token bus_token)
295*4882a593Smuzhiyun {
296*4882a593Smuzhiyun /* Exact match, unless qe_ic node is NULL */
297*4882a593Smuzhiyun struct device_node *of_node = irq_domain_get_of_node(h);
298*4882a593Smuzhiyun return of_node == NULL || of_node == node;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
qe_ic_host_map(struct irq_domain * h,unsigned int virq,irq_hw_number_t hw)301*4882a593Smuzhiyun static int qe_ic_host_map(struct irq_domain *h, unsigned int virq,
302*4882a593Smuzhiyun irq_hw_number_t hw)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun struct qe_ic *qe_ic = h->host_data;
305*4882a593Smuzhiyun struct irq_chip *chip;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (hw >= ARRAY_SIZE(qe_ic_info)) {
308*4882a593Smuzhiyun pr_err("%s: Invalid hw irq number for QEIC\n", __func__);
309*4882a593Smuzhiyun return -EINVAL;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun if (qe_ic_info[hw].mask == 0) {
313*4882a593Smuzhiyun printk(KERN_ERR "Can't map reserved IRQ\n");
314*4882a593Smuzhiyun return -EINVAL;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun /* Default chip */
317*4882a593Smuzhiyun chip = &qe_ic->hc_irq;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun irq_set_chip_data(virq, qe_ic);
320*4882a593Smuzhiyun irq_set_status_flags(virq, IRQ_LEVEL);
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun irq_set_chip_and_handler(virq, chip, handle_level_irq);
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun return 0;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun static const struct irq_domain_ops qe_ic_host_ops = {
328*4882a593Smuzhiyun .match = qe_ic_host_match,
329*4882a593Smuzhiyun .map = qe_ic_host_map,
330*4882a593Smuzhiyun .xlate = irq_domain_xlate_onetwocell,
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /* Return an interrupt vector or 0 if no interrupt is pending. */
qe_ic_get_low_irq(struct qe_ic * qe_ic)334*4882a593Smuzhiyun static unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun int irq;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun BUG_ON(qe_ic == NULL);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun /* get the interrupt source vector. */
341*4882a593Smuzhiyun irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun if (irq == 0)
344*4882a593Smuzhiyun return 0;
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun return irq_linear_revmap(qe_ic->irqhost, irq);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* Return an interrupt vector or 0 if no interrupt is pending. */
qe_ic_get_high_irq(struct qe_ic * qe_ic)350*4882a593Smuzhiyun static unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun int irq;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun BUG_ON(qe_ic == NULL);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* get the interrupt source vector. */
357*4882a593Smuzhiyun irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (irq == 0)
360*4882a593Smuzhiyun return 0;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun return irq_linear_revmap(qe_ic->irqhost, irq);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
qe_ic_cascade_low(struct irq_desc * desc)365*4882a593Smuzhiyun static void qe_ic_cascade_low(struct irq_desc *desc)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
368*4882a593Smuzhiyun unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
369*4882a593Smuzhiyun struct irq_chip *chip = irq_desc_get_chip(desc);
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (cascade_irq != 0)
372*4882a593Smuzhiyun generic_handle_irq(cascade_irq);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (chip->irq_eoi)
375*4882a593Smuzhiyun chip->irq_eoi(&desc->irq_data);
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
qe_ic_cascade_high(struct irq_desc * desc)378*4882a593Smuzhiyun static void qe_ic_cascade_high(struct irq_desc *desc)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
381*4882a593Smuzhiyun unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
382*4882a593Smuzhiyun struct irq_chip *chip = irq_desc_get_chip(desc);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun if (cascade_irq != 0)
385*4882a593Smuzhiyun generic_handle_irq(cascade_irq);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun if (chip->irq_eoi)
388*4882a593Smuzhiyun chip->irq_eoi(&desc->irq_data);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
qe_ic_cascade_muxed_mpic(struct irq_desc * desc)391*4882a593Smuzhiyun static void qe_ic_cascade_muxed_mpic(struct irq_desc *desc)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun struct qe_ic *qe_ic = irq_desc_get_handler_data(desc);
394*4882a593Smuzhiyun unsigned int cascade_irq;
395*4882a593Smuzhiyun struct irq_chip *chip = irq_desc_get_chip(desc);
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun cascade_irq = qe_ic_get_high_irq(qe_ic);
398*4882a593Smuzhiyun if (cascade_irq == 0)
399*4882a593Smuzhiyun cascade_irq = qe_ic_get_low_irq(qe_ic);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun if (cascade_irq != 0)
402*4882a593Smuzhiyun generic_handle_irq(cascade_irq);
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun chip->irq_eoi(&desc->irq_data);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
qe_ic_init(struct device_node * node)407*4882a593Smuzhiyun static void __init qe_ic_init(struct device_node *node)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun void (*low_handler)(struct irq_desc *desc);
410*4882a593Smuzhiyun void (*high_handler)(struct irq_desc *desc);
411*4882a593Smuzhiyun struct qe_ic *qe_ic;
412*4882a593Smuzhiyun struct resource res;
413*4882a593Smuzhiyun u32 ret;
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun ret = of_address_to_resource(node, 0, &res);
416*4882a593Smuzhiyun if (ret)
417*4882a593Smuzhiyun return;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL);
420*4882a593Smuzhiyun if (qe_ic == NULL)
421*4882a593Smuzhiyun return;
422*4882a593Smuzhiyun
423*4882a593Smuzhiyun qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS,
424*4882a593Smuzhiyun &qe_ic_host_ops, qe_ic);
425*4882a593Smuzhiyun if (qe_ic->irqhost == NULL) {
426*4882a593Smuzhiyun kfree(qe_ic);
427*4882a593Smuzhiyun return;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun qe_ic->regs = ioremap(res.start, resource_size(&res));
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun qe_ic->hc_irq = qe_ic_irq_chip;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun qe_ic->virq_high = irq_of_parse_and_map(node, 0);
435*4882a593Smuzhiyun qe_ic->virq_low = irq_of_parse_and_map(node, 1);
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (!qe_ic->virq_low) {
438*4882a593Smuzhiyun printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
439*4882a593Smuzhiyun kfree(qe_ic);
440*4882a593Smuzhiyun return;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun if (qe_ic->virq_high != qe_ic->virq_low) {
443*4882a593Smuzhiyun low_handler = qe_ic_cascade_low;
444*4882a593Smuzhiyun high_handler = qe_ic_cascade_high;
445*4882a593Smuzhiyun } else {
446*4882a593Smuzhiyun low_handler = qe_ic_cascade_muxed_mpic;
447*4882a593Smuzhiyun high_handler = NULL;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun qe_ic_write(qe_ic->regs, QEIC_CICR, 0);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun irq_set_handler_data(qe_ic->virq_low, qe_ic);
453*4882a593Smuzhiyun irq_set_chained_handler(qe_ic->virq_low, low_handler);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun if (qe_ic->virq_high && qe_ic->virq_high != qe_ic->virq_low) {
456*4882a593Smuzhiyun irq_set_handler_data(qe_ic->virq_high, qe_ic);
457*4882a593Smuzhiyun irq_set_chained_handler(qe_ic->virq_high, high_handler);
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun }
460*4882a593Smuzhiyun
qe_ic_of_init(void)461*4882a593Smuzhiyun static int __init qe_ic_of_init(void)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun struct device_node *np;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
466*4882a593Smuzhiyun if (!np) {
467*4882a593Smuzhiyun np = of_find_node_by_type(NULL, "qeic");
468*4882a593Smuzhiyun if (!np)
469*4882a593Smuzhiyun return -ENODEV;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun qe_ic_init(np);
472*4882a593Smuzhiyun of_node_put(np);
473*4882a593Smuzhiyun return 0;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun subsys_initcall(qe_ic_of_init);
476