1 // SPDX-License-Identifier: GPL-2.0-only
3 * Broadcom BCM6345 style Level 1 interrupt controller driver
5 * Copyright (C) 2014 Broadcom Corporation
6 * Copyright 2015 Simon Arlott
8 * This is based on the BCM7038 (which supports SMP) but with a single
9 * enable register instead of separate mask/set/clear registers.
11 * The BCM3380 has a similar mask/status register layout, but each pair
12 * of words is at separate locations (and SMP is not supported).
14 * ENABLE/STATUS words are packed next to each other for each CPU:
17 * 0x1000_0020: CPU0_W0_ENABLE
18 * 0x1000_0024: CPU0_W1_ENABLE
19 * 0x1000_0028: CPU0_W0_STATUS IRQs 31-63
20 * 0x1000_002c: CPU0_W1_STATUS IRQs 0-31
21 * 0x1000_0030: CPU1_W0_ENABLE
22 * 0x1000_0034: CPU1_W1_ENABLE
23 * 0x1000_0038: CPU1_W0_STATUS IRQs 31-63
24 * 0x1000_003c: CPU1_W1_STATUS IRQs 0-31
27 * 0x1000_0020: CPU0_W0_ENABLE
28 * 0x1000_0024: CPU0_W1_ENABLE
29 * 0x1000_0028: CPU0_W2_ENABLE
30 * 0x1000_002c: CPU0_W3_ENABLE
31 * 0x1000_0030: CPU0_W0_STATUS IRQs 96-127
32 * 0x1000_0034: CPU0_W1_STATUS IRQs 64-95
33 * 0x1000_0038: CPU0_W2_STATUS IRQs 32-63
34 * 0x1000_003c: CPU0_W3_STATUS IRQs 0-31
35 * 0x1000_0040: CPU1_W0_ENABLE
36 * 0x1000_0044: CPU1_W1_ENABLE
37 * 0x1000_0048: CPU1_W2_ENABLE
38 * 0x1000_004c: CPU1_W3_ENABLE
39 * 0x1000_0050: CPU1_W0_STATUS IRQs 96-127
40 * 0x1000_0054: CPU1_W1_STATUS IRQs 64-95
41 * 0x1000_0058: CPU1_W2_STATUS IRQs 32-63
42 * 0x1000_005c: CPU1_W3_STATUS IRQs 0-31
44 * IRQs are numbered in CPU native endian order
45 * (which is big-endian in these examples)
48 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
50 #include <linux/bitops.h>
51 #include <linux/cpumask.h>
52 #include <linux/kernel.h>
53 #include <linux/init.h>
54 #include <linux/interrupt.h>
56 #include <linux/ioport.h>
57 #include <linux/irq.h>
58 #include <linux/irqdomain.h>
59 #include <linux/module.h>
61 #include <linux/of_irq.h>
62 #include <linux/of_address.h>
63 #include <linux/of_platform.h>
64 #include <linux/platform_device.h>
65 #include <linux/slab.h>
66 #include <linux/smp.h>
67 #include <linux/types.h>
68 #include <linux/irqchip.h>
69 #include <linux/irqchip/chained_irq.h>
71 #define IRQS_PER_WORD 32
72 #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 2)
74 struct bcm6345_l1_cpu
;
76 struct bcm6345_l1_chip
{
79 struct irq_domain
*domain
;
80 struct cpumask cpumask
;
81 struct bcm6345_l1_cpu
*cpus
[NR_CPUS
];
84 struct bcm6345_l1_cpu
{
85 void __iomem
*map_base
;
86 unsigned int parent_irq
;
90 static inline unsigned int reg_enable(struct bcm6345_l1_chip
*intc
,
94 return (1 * intc
->n_words
- word
- 1) * sizeof(u32
);
96 return (0 * intc
->n_words
+ word
) * sizeof(u32
);
100 static inline unsigned int reg_status(struct bcm6345_l1_chip
*intc
,
104 return (2 * intc
->n_words
- word
- 1) * sizeof(u32
);
106 return (1 * intc
->n_words
+ word
) * sizeof(u32
);
110 static inline unsigned int cpu_for_irq(struct bcm6345_l1_chip
*intc
,
113 return cpumask_first_and(&intc
->cpumask
, irq_data_get_affinity_mask(d
));
116 static void bcm6345_l1_irq_handle(struct irq_desc
*desc
)
118 struct bcm6345_l1_chip
*intc
= irq_desc_get_handler_data(desc
);
119 struct bcm6345_l1_cpu
*cpu
;
120 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
124 cpu
= intc
->cpus
[cpu_logical_map(smp_processor_id())];
129 chained_irq_enter(chip
, desc
);
131 for (idx
= 0; idx
< intc
->n_words
; idx
++) {
132 int base
= idx
* IRQS_PER_WORD
;
133 unsigned long pending
;
134 irq_hw_number_t hwirq
;
137 pending
= __raw_readl(cpu
->map_base
+ reg_status(intc
, idx
));
138 pending
&= __raw_readl(cpu
->map_base
+ reg_enable(intc
, idx
));
140 for_each_set_bit(hwirq
, &pending
, IRQS_PER_WORD
) {
141 irq
= irq_linear_revmap(intc
->domain
, base
+ hwirq
);
145 spurious_interrupt();
149 chained_irq_exit(chip
, desc
);
152 static inline void __bcm6345_l1_unmask(struct irq_data
*d
)
154 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
155 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
156 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
157 unsigned int cpu_idx
= cpu_for_irq(intc
, d
);
159 intc
->cpus
[cpu_idx
]->enable_cache
[word
] |= mask
;
160 __raw_writel(intc
->cpus
[cpu_idx
]->enable_cache
[word
],
161 intc
->cpus
[cpu_idx
]->map_base
+ reg_enable(intc
, word
));
164 static inline void __bcm6345_l1_mask(struct irq_data
*d
)
166 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
167 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
168 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
169 unsigned int cpu_idx
= cpu_for_irq(intc
, d
);
171 intc
->cpus
[cpu_idx
]->enable_cache
[word
] &= ~mask
;
172 __raw_writel(intc
->cpus
[cpu_idx
]->enable_cache
[word
],
173 intc
->cpus
[cpu_idx
]->map_base
+ reg_enable(intc
, word
));
176 static void bcm6345_l1_unmask(struct irq_data
*d
)
178 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
181 raw_spin_lock_irqsave(&intc
->lock
, flags
);
182 __bcm6345_l1_unmask(d
);
183 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
186 static void bcm6345_l1_mask(struct irq_data
*d
)
188 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
191 raw_spin_lock_irqsave(&intc
->lock
, flags
);
192 __bcm6345_l1_mask(d
);
193 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
196 static int bcm6345_l1_set_affinity(struct irq_data
*d
,
197 const struct cpumask
*dest
,
200 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
201 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
202 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
203 unsigned int old_cpu
= cpu_for_irq(intc
, d
);
204 unsigned int new_cpu
;
205 struct cpumask valid
;
209 if (!cpumask_and(&valid
, &intc
->cpumask
, dest
))
212 new_cpu
= cpumask_any_and(&valid
, cpu_online_mask
);
213 if (new_cpu
>= nr_cpu_ids
)
216 dest
= cpumask_of(new_cpu
);
218 raw_spin_lock_irqsave(&intc
->lock
, flags
);
219 if (old_cpu
!= new_cpu
) {
220 enabled
= intc
->cpus
[old_cpu
]->enable_cache
[word
] & mask
;
222 __bcm6345_l1_mask(d
);
223 cpumask_copy(irq_data_get_affinity_mask(d
), dest
);
225 __bcm6345_l1_unmask(d
);
227 cpumask_copy(irq_data_get_affinity_mask(d
), dest
);
229 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
231 irq_data_update_effective_affinity(d
, cpumask_of(new_cpu
));
233 return IRQ_SET_MASK_OK_NOCOPY
;
236 static int __init
bcm6345_l1_init_one(struct device_node
*dn
,
238 struct bcm6345_l1_chip
*intc
)
242 struct bcm6345_l1_cpu
*cpu
;
243 unsigned int i
, n_words
;
245 if (of_address_to_resource(dn
, idx
, &res
))
247 sz
= resource_size(&res
);
248 n_words
= sz
/ REG_BYTES_PER_IRQ_WORD
;
251 intc
->n_words
= n_words
;
252 else if (intc
->n_words
!= n_words
)
255 cpu
= intc
->cpus
[idx
] = kzalloc(sizeof(*cpu
) + n_words
* sizeof(u32
),
260 cpu
->map_base
= ioremap(res
.start
, sz
);
264 for (i
= 0; i
< n_words
; i
++) {
265 cpu
->enable_cache
[i
] = 0;
266 __raw_writel(0, cpu
->map_base
+ reg_enable(intc
, i
));
269 cpu
->parent_irq
= irq_of_parse_and_map(dn
, idx
);
270 if (!cpu
->parent_irq
) {
271 pr_err("failed to map parent interrupt %d\n", cpu
->parent_irq
);
274 irq_set_chained_handler_and_data(cpu
->parent_irq
,
275 bcm6345_l1_irq_handle
, intc
);
280 static struct irq_chip bcm6345_l1_irq_chip
= {
281 .name
= "bcm6345-l1",
282 .irq_mask
= bcm6345_l1_mask
,
283 .irq_unmask
= bcm6345_l1_unmask
,
284 .irq_set_affinity
= bcm6345_l1_set_affinity
,
287 static int bcm6345_l1_map(struct irq_domain
*d
, unsigned int virq
,
288 irq_hw_number_t hw_irq
)
290 irq_set_chip_and_handler(virq
,
291 &bcm6345_l1_irq_chip
, handle_percpu_irq
);
292 irq_set_chip_data(virq
, d
->host_data
);
293 irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq
)));
297 static const struct irq_domain_ops bcm6345_l1_domain_ops
= {
298 .xlate
= irq_domain_xlate_onecell
,
299 .map
= bcm6345_l1_map
,
302 static int __init
bcm6345_l1_of_init(struct device_node
*dn
,
303 struct device_node
*parent
)
305 struct bcm6345_l1_chip
*intc
;
309 intc
= kzalloc(sizeof(*intc
), GFP_KERNEL
);
313 for_each_possible_cpu(idx
) {
314 ret
= bcm6345_l1_init_one(dn
, idx
, intc
);
316 pr_err("failed to init intc L1 for cpu %d: %d\n",
319 cpumask_set_cpu(idx
, &intc
->cpumask
);
322 if (!cpumask_weight(&intc
->cpumask
)) {
327 raw_spin_lock_init(&intc
->lock
);
329 intc
->domain
= irq_domain_add_linear(dn
, IRQS_PER_WORD
* intc
->n_words
,
330 &bcm6345_l1_domain_ops
,
337 pr_info("registered BCM6345 L1 intc (IRQs: %d)\n",
338 IRQS_PER_WORD
* intc
->n_words
);
339 for_each_cpu(idx
, &intc
->cpumask
) {
340 struct bcm6345_l1_cpu
*cpu
= intc
->cpus
[idx
];
342 pr_info(" CPU%u at MMIO 0x%p (irq = %d)\n", idx
,
343 cpu
->map_base
, cpu
->parent_irq
);
349 for_each_possible_cpu(idx
) {
350 struct bcm6345_l1_cpu
*cpu
= intc
->cpus
[idx
];
354 iounmap(cpu
->map_base
);
363 IRQCHIP_DECLARE(bcm6345_l1
, "brcm,bcm6345-l1-intc", bcm6345_l1_of_init
);