2 * Generic Broadcom Set Top Box 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.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18 #include <linux/init.h>
19 #include <linux/slab.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
23 #include <linux/of_irq.h>
24 #include <linux/of_address.h>
25 #include <linux/of_platform.h>
26 #include <linux/interrupt.h>
27 #include <linux/irq.h>
29 #include <linux/irqdomain.h>
30 #include <linux/irqchip.h>
31 #include <linux/irqchip/chained_irq.h>
33 #include <asm/mach/irq.h>
37 /* Register offsets in the L2 interrupt controller */
38 #define CPU_STATUS 0x00
40 #define CPU_CLEAR 0x08
41 #define CPU_MASK_STATUS 0x0c
42 #define CPU_MASK_SET 0x10
43 #define CPU_MASK_CLEAR 0x14
45 /* L2 intc private data structure */
46 struct brcmstb_l2_intc_data
{
49 struct irq_domain
*domain
;
51 u32 saved_mask
; /* for suspend/resume */
54 static void brcmstb_l2_intc_irq_handle(unsigned int irq
, struct irq_desc
*desc
)
56 struct brcmstb_l2_intc_data
*b
= irq_desc_get_handler_data(desc
);
57 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
60 chained_irq_enter(chip
, desc
);
62 status
= __raw_readl(b
->base
+ CPU_STATUS
) &
63 ~(__raw_readl(b
->base
+ CPU_MASK_STATUS
));
66 do_bad_IRQ(irq
, desc
);
71 irq
= ffs(status
) - 1;
72 /* ack at our level */
73 __raw_writel(1 << irq
, b
->base
+ CPU_CLEAR
);
74 status
&= ~(1 << irq
);
75 generic_handle_irq(irq_find_mapping(b
->domain
, irq
));
78 chained_irq_exit(chip
, desc
);
81 static void brcmstb_l2_intc_suspend(struct irq_data
*d
)
83 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
84 struct brcmstb_l2_intc_data
*b
= gc
->private;
87 /* Save the current mask */
88 b
->saved_mask
= __raw_readl(b
->base
+ CPU_MASK_STATUS
);
91 /* Program the wakeup mask */
92 __raw_writel(~gc
->wake_active
, b
->base
+ CPU_MASK_SET
);
93 __raw_writel(gc
->wake_active
, b
->base
+ CPU_MASK_CLEAR
);
98 static void brcmstb_l2_intc_resume(struct irq_data
*d
)
100 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
101 struct brcmstb_l2_intc_data
*b
= gc
->private;
104 /* Clear unmasked non-wakeup interrupts */
105 __raw_writel(~b
->saved_mask
& ~gc
->wake_active
, b
->base
+ CPU_CLEAR
);
107 /* Restore the saved mask */
108 __raw_writel(b
->saved_mask
, b
->base
+ CPU_MASK_SET
);
109 __raw_writel(~b
->saved_mask
, b
->base
+ CPU_MASK_CLEAR
);
113 int __init
brcmstb_l2_intc_of_init(struct device_node
*np
,
114 struct device_node
*parent
)
116 unsigned int clr
= IRQ_NOREQUEST
| IRQ_NOPROBE
| IRQ_NOAUTOEN
;
117 struct brcmstb_l2_intc_data
*data
;
118 struct irq_chip_generic
*gc
;
119 struct irq_chip_type
*ct
;
122 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
126 data
->base
= of_iomap(np
, 0);
128 pr_err("failed to remap intc L2 registers\n");
133 /* Disable all interrupts by default */
134 __raw_writel(0xffffffff, data
->base
+ CPU_MASK_SET
);
135 __raw_writel(0xffffffff, data
->base
+ CPU_CLEAR
);
137 data
->parent_irq
= irq_of_parse_and_map(np
, 0);
138 if (data
->parent_irq
< 0) {
139 pr_err("failed to find parent interrupt\n");
140 ret
= data
->parent_irq
;
144 data
->domain
= irq_domain_add_linear(np
, 32,
145 &irq_generic_chip_ops
, NULL
);
151 /* Allocate a single Generic IRQ chip for this node */
152 ret
= irq_alloc_domain_generic_chips(data
->domain
, 32, 1,
153 np
->full_name
, handle_edge_irq
, clr
, 0, 0);
155 pr_err("failed to allocate generic irq chip\n");
156 goto out_free_domain
;
159 /* Set the IRQ chaining logic */
160 irq_set_handler_data(data
->parent_irq
, data
);
161 irq_set_chained_handler(data
->parent_irq
, brcmstb_l2_intc_irq_handle
);
163 gc
= irq_get_domain_generic_chip(data
->domain
, 0);
164 gc
->reg_base
= data
->base
;
168 ct
->chip
.irq_ack
= irq_gc_ack_set_bit
;
169 ct
->regs
.ack
= CPU_CLEAR
;
171 ct
->chip
.irq_mask
= irq_gc_mask_disable_reg
;
172 ct
->regs
.disable
= CPU_MASK_SET
;
174 ct
->chip
.irq_unmask
= irq_gc_unmask_enable_reg
;
175 ct
->regs
.enable
= CPU_MASK_CLEAR
;
177 ct
->chip
.irq_suspend
= brcmstb_l2_intc_suspend
;
178 ct
->chip
.irq_resume
= brcmstb_l2_intc_resume
;
180 if (of_property_read_bool(np
, "brcm,irq-can-wake")) {
181 data
->can_wake
= true;
182 /* This IRQ chip can wake the system, set all child interrupts
183 * in wake_enabled mask
185 gc
->wake_enabled
= 0xffffffff;
186 ct
->chip
.irq_set_wake
= irq_gc_set_wake
;
189 pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n",
190 data
->base
, data
->parent_irq
);
195 irq_domain_remove(data
->domain
);
202 IRQCHIP_DECLARE(brcmstb_l2_intc
, "brcm,l2-intc", brcmstb_l2_intc_of_init
);