2 * Broadcom BCM6345 style Level 1 interrupt controller driver
4 * Copyright (C) 2014 Broadcom Corporation
5 * Copyright 2015 Simon Arlott
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This is based on the BCM7038 (which supports SMP) but with a single
12 * enable register instead of separate mask/set/clear registers.
14 * The BCM3380 has a similar mask/status register layout, but each pair
15 * of words is at separate locations (and SMP is not supported).
17 * ENABLE/STATUS words are packed next to each other for each CPU:
20 * 0x1000_0020: CPU0_W0_ENABLE
21 * 0x1000_0024: CPU0_W1_ENABLE
22 * 0x1000_0028: CPU0_W0_STATUS IRQs 31-63
23 * 0x1000_002c: CPU0_W1_STATUS IRQs 0-31
24 * 0x1000_0030: CPU1_W0_ENABLE
25 * 0x1000_0034: CPU1_W1_ENABLE
26 * 0x1000_0038: CPU1_W0_STATUS IRQs 31-63
27 * 0x1000_003c: CPU1_W1_STATUS IRQs 0-31
30 * 0x1000_0020: CPU0_W0_ENABLE
31 * 0x1000_0024: CPU0_W1_ENABLE
32 * 0x1000_0028: CPU0_W2_ENABLE
33 * 0x1000_002c: CPU0_W3_ENABLE
34 * 0x1000_0030: CPU0_W0_STATUS IRQs 96-127
35 * 0x1000_0034: CPU0_W1_STATUS IRQs 64-95
36 * 0x1000_0038: CPU0_W2_STATUS IRQs 32-63
37 * 0x1000_003c: CPU0_W3_STATUS IRQs 0-31
38 * 0x1000_0040: CPU1_W0_ENABLE
39 * 0x1000_0044: CPU1_W1_ENABLE
40 * 0x1000_0048: CPU1_W2_ENABLE
41 * 0x1000_004c: CPU1_W3_ENABLE
42 * 0x1000_0050: CPU1_W0_STATUS IRQs 96-127
43 * 0x1000_0054: CPU1_W1_STATUS IRQs 64-95
44 * 0x1000_0058: CPU1_W2_STATUS IRQs 32-63
45 * 0x1000_005c: CPU1_W3_STATUS IRQs 0-31
47 * IRQs are numbered in CPU native endian order
48 * (which is big-endian in these examples)
51 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
53 #include <linux/bitops.h>
54 #include <linux/cpumask.h>
55 #include <linux/kconfig.h>
56 #include <linux/kernel.h>
57 #include <linux/init.h>
58 #include <linux/interrupt.h>
60 #include <linux/ioport.h>
61 #include <linux/irq.h>
62 #include <linux/irqdomain.h>
63 #include <linux/module.h>
65 #include <linux/of_irq.h>
66 #include <linux/of_address.h>
67 #include <linux/of_platform.h>
68 #include <linux/platform_device.h>
69 #include <linux/slab.h>
70 #include <linux/smp.h>
71 #include <linux/types.h>
72 #include <linux/irqchip.h>
73 #include <linux/irqchip/chained_irq.h>
75 #define IRQS_PER_WORD 32
76 #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 2)
78 struct bcm6345_l1_cpu
;
80 struct bcm6345_l1_chip
{
83 struct irq_domain
*domain
;
84 struct cpumask cpumask
;
85 struct bcm6345_l1_cpu
*cpus
[NR_CPUS
];
88 struct bcm6345_l1_cpu
{
89 void __iomem
*map_base
;
90 unsigned int parent_irq
;
94 static inline unsigned int reg_enable(struct bcm6345_l1_chip
*intc
,
98 return (1 * intc
->n_words
- word
- 1) * sizeof(u32
);
100 return (0 * intc
->n_words
+ word
) * sizeof(u32
);
104 static inline unsigned int reg_status(struct bcm6345_l1_chip
*intc
,
108 return (2 * intc
->n_words
- word
- 1) * sizeof(u32
);
110 return (1 * intc
->n_words
+ word
) * sizeof(u32
);
114 static inline unsigned int cpu_for_irq(struct bcm6345_l1_chip
*intc
,
117 return cpumask_first_and(&intc
->cpumask
, irq_data_get_affinity_mask(d
));
120 static void bcm6345_l1_irq_handle(struct irq_desc
*desc
)
122 struct bcm6345_l1_chip
*intc
= irq_desc_get_handler_data(desc
);
123 struct bcm6345_l1_cpu
*cpu
;
124 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
128 cpu
= intc
->cpus
[cpu_logical_map(smp_processor_id())];
133 chained_irq_enter(chip
, desc
);
135 for (idx
= 0; idx
< intc
->n_words
; idx
++) {
136 int base
= idx
* IRQS_PER_WORD
;
137 unsigned long pending
;
138 irq_hw_number_t hwirq
;
141 pending
= __raw_readl(cpu
->map_base
+ reg_status(intc
, idx
));
142 pending
&= __raw_readl(cpu
->map_base
+ reg_enable(intc
, idx
));
144 for_each_set_bit(hwirq
, &pending
, IRQS_PER_WORD
) {
145 irq
= irq_linear_revmap(intc
->domain
, base
+ hwirq
);
149 spurious_interrupt();
153 chained_irq_exit(chip
, desc
);
156 static inline void __bcm6345_l1_unmask(struct irq_data
*d
)
158 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
159 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
160 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
161 unsigned int cpu_idx
= cpu_for_irq(intc
, d
);
163 intc
->cpus
[cpu_idx
]->enable_cache
[word
] |= mask
;
164 __raw_writel(intc
->cpus
[cpu_idx
]->enable_cache
[word
],
165 intc
->cpus
[cpu_idx
]->map_base
+ reg_enable(intc
, word
));
168 static inline void __bcm6345_l1_mask(struct irq_data
*d
)
170 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
171 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
172 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
173 unsigned int cpu_idx
= cpu_for_irq(intc
, d
);
175 intc
->cpus
[cpu_idx
]->enable_cache
[word
] &= ~mask
;
176 __raw_writel(intc
->cpus
[cpu_idx
]->enable_cache
[word
],
177 intc
->cpus
[cpu_idx
]->map_base
+ reg_enable(intc
, word
));
180 static void bcm6345_l1_unmask(struct irq_data
*d
)
182 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
185 raw_spin_lock_irqsave(&intc
->lock
, flags
);
186 __bcm6345_l1_unmask(d
);
187 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
190 static void bcm6345_l1_mask(struct irq_data
*d
)
192 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
195 raw_spin_lock_irqsave(&intc
->lock
, flags
);
196 __bcm6345_l1_mask(d
);
197 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
200 static int bcm6345_l1_set_affinity(struct irq_data
*d
,
201 const struct cpumask
*dest
,
204 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
205 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
206 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
207 unsigned int old_cpu
= cpu_for_irq(intc
, d
);
208 unsigned int new_cpu
;
209 struct cpumask valid
;
213 if (!cpumask_and(&valid
, &intc
->cpumask
, dest
))
216 new_cpu
= cpumask_any_and(&valid
, cpu_online_mask
);
217 if (new_cpu
>= nr_cpu_ids
)
220 dest
= cpumask_of(new_cpu
);
222 raw_spin_lock_irqsave(&intc
->lock
, flags
);
223 if (old_cpu
!= new_cpu
) {
224 enabled
= intc
->cpus
[old_cpu
]->enable_cache
[word
] & mask
;
226 __bcm6345_l1_mask(d
);
227 cpumask_copy(irq_data_get_affinity_mask(d
), dest
);
229 __bcm6345_l1_unmask(d
);
231 cpumask_copy(irq_data_get_affinity_mask(d
), dest
);
233 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
235 return IRQ_SET_MASK_OK_NOCOPY
;
238 static int __init
bcm6345_l1_init_one(struct device_node
*dn
,
240 struct bcm6345_l1_chip
*intc
)
244 struct bcm6345_l1_cpu
*cpu
;
245 unsigned int i
, n_words
;
247 if (of_address_to_resource(dn
, idx
, &res
))
249 sz
= resource_size(&res
);
250 n_words
= sz
/ REG_BYTES_PER_IRQ_WORD
;
253 intc
->n_words
= n_words
;
254 else if (intc
->n_words
!= n_words
)
257 cpu
= intc
->cpus
[idx
] = kzalloc(sizeof(*cpu
) + n_words
* sizeof(u32
),
262 cpu
->map_base
= ioremap(res
.start
, sz
);
266 for (i
= 0; i
< n_words
; i
++) {
267 cpu
->enable_cache
[i
] = 0;
268 __raw_writel(0, cpu
->map_base
+ reg_enable(intc
, i
));
271 cpu
->parent_irq
= irq_of_parse_and_map(dn
, idx
);
272 if (!cpu
->parent_irq
) {
273 pr_err("failed to map parent interrupt %d\n", cpu
->parent_irq
);
276 irq_set_chained_handler_and_data(cpu
->parent_irq
,
277 bcm6345_l1_irq_handle
, intc
);
282 static struct irq_chip bcm6345_l1_irq_chip
= {
283 .name
= "bcm6345-l1",
284 .irq_mask
= bcm6345_l1_mask
,
285 .irq_unmask
= bcm6345_l1_unmask
,
286 .irq_set_affinity
= bcm6345_l1_set_affinity
,
289 static int bcm6345_l1_map(struct irq_domain
*d
, unsigned int virq
,
290 irq_hw_number_t hw_irq
)
292 irq_set_chip_and_handler(virq
,
293 &bcm6345_l1_irq_chip
, handle_percpu_irq
);
294 irq_set_chip_data(virq
, d
->host_data
);
298 static const struct irq_domain_ops bcm6345_l1_domain_ops
= {
299 .xlate
= irq_domain_xlate_onecell
,
300 .map
= bcm6345_l1_map
,
303 static int __init
bcm6345_l1_of_init(struct device_node
*dn
,
304 struct device_node
*parent
)
306 struct bcm6345_l1_chip
*intc
;
310 intc
= kzalloc(sizeof(*intc
), GFP_KERNEL
);
314 for_each_possible_cpu(idx
) {
315 ret
= bcm6345_l1_init_one(dn
, idx
, intc
);
317 pr_err("failed to init intc L1 for cpu %d: %d\n",
320 cpumask_set_cpu(idx
, &intc
->cpumask
);
323 if (!cpumask_weight(&intc
->cpumask
)) {
328 raw_spin_lock_init(&intc
->lock
);
330 intc
->domain
= irq_domain_add_linear(dn
, IRQS_PER_WORD
* intc
->n_words
,
331 &bcm6345_l1_domain_ops
,
338 pr_info("registered BCM6345 L1 intc (IRQs: %d)\n",
339 IRQS_PER_WORD
* intc
->n_words
);
340 for_each_cpu(idx
, &intc
->cpumask
) {
341 struct bcm6345_l1_cpu
*cpu
= intc
->cpus
[idx
];
343 pr_info(" CPU%u at MMIO 0x%p (irq = %d)\n", idx
,
344 cpu
->map_base
, cpu
->parent_irq
);
350 for_each_possible_cpu(idx
) {
351 struct bcm6345_l1_cpu
*cpu
= intc
->cpus
[idx
];
355 iounmap(cpu
->map_base
);
364 IRQCHIP_DECLARE(bcm6345_l1
, "brcm,bcm6345-l1-intc", bcm6345_l1_of_init
);