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>
22 #include <linux/spinlock.h>
24 #include <linux/of_irq.h>
25 #include <linux/of_address.h>
26 #include <linux/of_platform.h>
27 #include <linux/interrupt.h>
28 #include <linux/irq.h>
30 #include <linux/irqdomain.h>
31 #include <linux/irqchip.h>
32 #include <linux/irqchip/chained_irq.h>
34 /* Register offsets in the L2 interrupt controller */
35 #define CPU_STATUS 0x00
37 #define CPU_CLEAR 0x08
38 #define CPU_MASK_STATUS 0x0c
39 #define CPU_MASK_SET 0x10
40 #define CPU_MASK_CLEAR 0x14
42 /* L2 intc private data structure */
43 struct brcmstb_l2_intc_data
{
46 struct irq_domain
*domain
;
48 u32 saved_mask
; /* for suspend/resume */
51 static void brcmstb_l2_intc_irq_handle(struct irq_desc
*desc
)
53 struct brcmstb_l2_intc_data
*b
= irq_desc_get_handler_data(desc
);
54 struct irq_chip_generic
*gc
= irq_get_domain_generic_chip(b
->domain
, 0);
55 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
59 chained_irq_enter(chip
, desc
);
61 status
= irq_reg_readl(gc
, CPU_STATUS
) &
62 ~(irq_reg_readl(gc
, CPU_MASK_STATUS
));
65 raw_spin_lock(&desc
->lock
);
67 raw_spin_unlock(&desc
->lock
);
72 irq
= ffs(status
) - 1;
73 /* ack at our level */
74 irq_reg_writel(gc
, 1 << irq
, CPU_CLEAR
);
75 status
&= ~(1 << irq
);
76 generic_handle_irq(irq_find_mapping(b
->domain
, irq
));
79 chained_irq_exit(chip
, desc
);
82 static void brcmstb_l2_intc_suspend(struct irq_data
*d
)
84 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
85 struct brcmstb_l2_intc_data
*b
= gc
->private;
88 /* Save the current mask */
89 b
->saved_mask
= irq_reg_readl(gc
, CPU_MASK_STATUS
);
92 /* Program the wakeup mask */
93 irq_reg_writel(gc
, ~gc
->wake_active
, CPU_MASK_SET
);
94 irq_reg_writel(gc
, gc
->wake_active
, CPU_MASK_CLEAR
);
99 static void brcmstb_l2_intc_resume(struct irq_data
*d
)
101 struct irq_chip_generic
*gc
= irq_data_get_irq_chip_data(d
);
102 struct brcmstb_l2_intc_data
*b
= gc
->private;
105 /* Clear unmasked non-wakeup interrupts */
106 irq_reg_writel(gc
, ~b
->saved_mask
& ~gc
->wake_active
, CPU_CLEAR
);
108 /* Restore the saved mask */
109 irq_reg_writel(gc
, b
->saved_mask
, CPU_MASK_SET
);
110 irq_reg_writel(gc
, ~b
->saved_mask
, CPU_MASK_CLEAR
);
114 static int __init
brcmstb_l2_intc_of_init(struct device_node
*np
,
115 struct device_node
*parent
)
117 unsigned int clr
= IRQ_NOREQUEST
| IRQ_NOPROBE
| IRQ_NOAUTOEN
;
118 struct brcmstb_l2_intc_data
*data
;
119 struct irq_chip_generic
*gc
;
120 struct irq_chip_type
*ct
;
124 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
128 data
->base
= of_iomap(np
, 0);
130 pr_err("failed to remap intc L2 registers\n");
135 /* Disable all interrupts by default */
136 writel(0xffffffff, data
->base
+ CPU_MASK_SET
);
138 /* Wakeup interrupts may be retained from S5 (cold boot) */
139 data
->can_wake
= of_property_read_bool(np
, "brcm,irq-can-wake");
141 writel(0xffffffff, data
->base
+ CPU_CLEAR
);
143 data
->parent_irq
= irq_of_parse_and_map(np
, 0);
144 if (!data
->parent_irq
) {
145 pr_err("failed to find parent interrupt\n");
150 data
->domain
= irq_domain_add_linear(np
, 32,
151 &irq_generic_chip_ops
, NULL
);
157 /* MIPS chips strapped for BE will automagically configure the
158 * peripheral registers for CPU-native byte order.
161 if (IS_ENABLED(CONFIG_MIPS
) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN
))
162 flags
|= IRQ_GC_BE_IO
;
164 /* Allocate a single Generic IRQ chip for this node */
165 ret
= irq_alloc_domain_generic_chips(data
->domain
, 32, 1,
166 np
->full_name
, handle_edge_irq
, clr
, 0, flags
);
168 pr_err("failed to allocate generic irq chip\n");
169 goto out_free_domain
;
172 /* Set the IRQ chaining logic */
173 irq_set_chained_handler_and_data(data
->parent_irq
,
174 brcmstb_l2_intc_irq_handle
, data
);
176 gc
= irq_get_domain_generic_chip(data
->domain
, 0);
177 gc
->reg_base
= data
->base
;
181 ct
->chip
.irq_ack
= irq_gc_ack_set_bit
;
182 ct
->regs
.ack
= CPU_CLEAR
;
184 ct
->chip
.irq_mask
= irq_gc_mask_disable_reg
;
185 ct
->regs
.disable
= CPU_MASK_SET
;
187 ct
->chip
.irq_unmask
= irq_gc_unmask_enable_reg
;
188 ct
->regs
.enable
= CPU_MASK_CLEAR
;
190 ct
->chip
.irq_suspend
= brcmstb_l2_intc_suspend
;
191 ct
->chip
.irq_resume
= brcmstb_l2_intc_resume
;
193 if (data
->can_wake
) {
194 /* This IRQ chip can wake the system, set all child interrupts
195 * in wake_enabled mask
197 gc
->wake_enabled
= 0xffffffff;
198 ct
->chip
.irq_set_wake
= irq_gc_set_wake
;
201 pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n",
202 data
->base
, data
->parent_irq
);
207 irq_domain_remove(data
->domain
);
214 IRQCHIP_DECLARE(brcmstb_l2_intc
, "brcm,l2-intc", brcmstb_l2_intc_of_init
);