2 * Broadcom BCM7120 style Level 2 interrupt controller driver
4 * Copyright (C) 2014 Broadcom Corporation
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13 #include <linux/init.h>
14 #include <linux/slab.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
18 #include <linux/of_irq.h>
19 #include <linux/of_address.h>
20 #include <linux/of_platform.h>
21 #include <linux/interrupt.h>
22 #include <linux/irq.h>
24 #include <linux/irqdomain.h>
25 #include <linux/reboot.h>
26 #include <linux/irqchip/chained_irq.h>
30 #include <asm/mach/irq.h>
32 /* Register offset in the L2 interrupt controller */
36 struct bcm7120_l2_intc_data
{
38 struct irq_domain
*domain
;
45 static void bcm7120_l2_intc_irq_handle(unsigned int irq
, struct irq_desc
*desc
)
47 struct bcm7120_l2_intc_data
*b
= irq_desc_get_handler_data(desc
);
48 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
51 chained_irq_enter(chip
, desc
);
53 status
= __raw_readl(b
->base
+ IRQSTAT
);
56 do_bad_IRQ(irq
, desc
);
61 irq
= ffs(status
) - 1;
62 status
&= ~(1 << irq
);
63 generic_handle_irq(irq_find_mapping(b
->domain
, irq
));
67 chained_irq_exit(chip
, desc
);
70 static void bcm7120_l2_intc_suspend(struct irq_data
*d
)
72 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
73 struct bcm7120_l2_intc_data
*b
= gc
->private;
77 /* Save the current mask and the interrupt forward mask */
78 b
->saved_mask
= __raw_readl(b
->base
) | b
->irq_fwd_mask
;
80 reg
= b
->saved_mask
| gc
->wake_active
;
81 __raw_writel(reg
, b
->base
);
86 static void bcm7120_l2_intc_resume(struct irq_data
*d
)
88 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
89 struct bcm7120_l2_intc_data
*b
= gc
->private;
91 /* Restore the saved mask */
93 __raw_writel(b
->saved_mask
, b
->base
);
97 static int bcm7120_l2_intc_init_one(struct device_node
*dn
,
98 struct bcm7120_l2_intc_data
*data
,
99 int irq
, const __be32
*map_mask
)
103 parent_irq
= irq_of_parse_and_map(dn
, irq
);
104 if (parent_irq
< 0) {
105 pr_err("failed to map interrupt %d\n", irq
);
109 data
->irq_map_mask
|= be32_to_cpup(map_mask
+ irq
);
111 irq_set_handler_data(parent_irq
, data
);
112 irq_set_chained_handler(parent_irq
, bcm7120_l2_intc_irq_handle
);
117 int __init
bcm7120_l2_intc_of_init(struct device_node
*dn
,
118 struct device_node
*parent
)
120 unsigned int clr
= IRQ_NOREQUEST
| IRQ_NOPROBE
| IRQ_NOAUTOEN
;
121 struct bcm7120_l2_intc_data
*data
;
122 struct irq_chip_generic
*gc
;
123 struct irq_chip_type
*ct
;
124 const __be32
*map_mask
;
126 int ret
= 0, len
, irq
;
128 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
132 data
->base
= of_iomap(dn
, 0);
134 pr_err("failed to remap intc L2 registers\n");
139 if (of_property_read_u32(dn
, "brcm,int-fwd-mask", &data
->irq_fwd_mask
))
140 data
->irq_fwd_mask
= 0;
142 /* Enable all interrupt specified in the interrupt forward mask and have
145 __raw_writel(data
->irq_fwd_mask
, data
->base
+ IRQEN
);
147 num_parent_irqs
= of_irq_count(dn
);
148 if (num_parent_irqs
<= 0) {
149 pr_err("invalid number of parent interrupts\n");
154 map_mask
= of_get_property(dn
, "brcm,int-map-mask", &len
);
155 if (!map_mask
|| (len
!= (sizeof(*map_mask
) * num_parent_irqs
))) {
156 pr_err("invalid brcm,int-map-mask property\n");
161 for (irq
= 0; irq
< num_parent_irqs
; irq
++) {
162 ret
= bcm7120_l2_intc_init_one(dn
, data
, irq
, map_mask
);
167 data
->domain
= irq_domain_add_linear(dn
, 32,
168 &irq_generic_chip_ops
, NULL
);
174 ret
= irq_alloc_domain_generic_chips(data
->domain
, 32, 1,
175 dn
->full_name
, handle_level_irq
, clr
, 0,
176 IRQ_GC_INIT_MASK_CACHE
);
178 pr_err("failed to allocate generic irq chip\n");
179 goto out_free_domain
;
182 gc
= irq_get_domain_generic_chip(data
->domain
, 0);
183 gc
->unused
= 0xfffffff & ~data
->irq_map_mask
;
184 gc
->reg_base
= data
->base
;
188 ct
->regs
.mask
= IRQEN
;
189 ct
->chip
.irq_mask
= irq_gc_mask_clr_bit
;
190 ct
->chip
.irq_unmask
= irq_gc_mask_set_bit
;
191 ct
->chip
.irq_ack
= irq_gc_noop
;
192 ct
->chip
.irq_suspend
= bcm7120_l2_intc_suspend
;
193 ct
->chip
.irq_resume
= bcm7120_l2_intc_resume
;
195 if (of_property_read_bool(dn
, "brcm,irq-can-wake")) {
196 data
->can_wake
= true;
197 /* This IRQ chip can wake the system, set all relevant child
198 * interupts in wake_enabled mask
200 gc
->wake_enabled
= 0xffffffff;
201 gc
->wake_enabled
&= ~gc
->unused
;
202 ct
->chip
.irq_set_wake
= irq_gc_set_wake
;
205 pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n",
206 data
->base
, num_parent_irqs
);
211 irq_domain_remove(data
->domain
);
218 IRQCHIP_DECLARE(brcmstb_l2_intc
, "brcm,bcm7120-l2-intc",
219 bcm7120_l2_intc_of_init
);