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/kernel.h>
56 #include <linux/init.h>
57 #include <linux/interrupt.h>
59 #include <linux/ioport.h>
60 #include <linux/irq.h>
61 #include <linux/irqdomain.h>
62 #include <linux/module.h>
64 #include <linux/of_irq.h>
65 #include <linux/of_address.h>
66 #include <linux/of_platform.h>
67 #include <linux/platform_device.h>
68 #include <linux/slab.h>
69 #include <linux/smp.h>
70 #include <linux/types.h>
71 #include <linux/irqchip.h>
72 #include <linux/irqchip/chained_irq.h>
74 #define IRQS_PER_WORD 32
75 #define REG_BYTES_PER_IRQ_WORD (sizeof(u32) * 2)
77 struct bcm6345_l1_cpu
;
79 struct bcm6345_l1_chip
{
82 struct irq_domain
*domain
;
83 struct cpumask cpumask
;
84 struct bcm6345_l1_cpu
*cpus
[NR_CPUS
];
87 struct bcm6345_l1_cpu
{
88 void __iomem
*map_base
;
89 unsigned int parent_irq
;
93 static inline unsigned int reg_enable(struct bcm6345_l1_chip
*intc
,
97 return (1 * intc
->n_words
- word
- 1) * sizeof(u32
);
99 return (0 * intc
->n_words
+ word
) * sizeof(u32
);
103 static inline unsigned int reg_status(struct bcm6345_l1_chip
*intc
,
107 return (2 * intc
->n_words
- word
- 1) * sizeof(u32
);
109 return (1 * intc
->n_words
+ word
) * sizeof(u32
);
113 static inline unsigned int cpu_for_irq(struct bcm6345_l1_chip
*intc
,
116 return cpumask_first_and(&intc
->cpumask
, irq_data_get_affinity_mask(d
));
119 static void bcm6345_l1_irq_handle(struct irq_desc
*desc
)
121 struct bcm6345_l1_chip
*intc
= irq_desc_get_handler_data(desc
);
122 struct bcm6345_l1_cpu
*cpu
;
123 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
127 cpu
= intc
->cpus
[cpu_logical_map(smp_processor_id())];
132 chained_irq_enter(chip
, desc
);
134 for (idx
= 0; idx
< intc
->n_words
; idx
++) {
135 int base
= idx
* IRQS_PER_WORD
;
136 unsigned long pending
;
137 irq_hw_number_t hwirq
;
140 pending
= __raw_readl(cpu
->map_base
+ reg_status(intc
, idx
));
141 pending
&= __raw_readl(cpu
->map_base
+ reg_enable(intc
, idx
));
143 for_each_set_bit(hwirq
, &pending
, IRQS_PER_WORD
) {
144 irq
= irq_linear_revmap(intc
->domain
, base
+ hwirq
);
148 spurious_interrupt();
152 chained_irq_exit(chip
, desc
);
155 static inline void __bcm6345_l1_unmask(struct irq_data
*d
)
157 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
158 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
159 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
160 unsigned int cpu_idx
= cpu_for_irq(intc
, d
);
162 intc
->cpus
[cpu_idx
]->enable_cache
[word
] |= mask
;
163 __raw_writel(intc
->cpus
[cpu_idx
]->enable_cache
[word
],
164 intc
->cpus
[cpu_idx
]->map_base
+ reg_enable(intc
, word
));
167 static inline void __bcm6345_l1_mask(struct irq_data
*d
)
169 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
170 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
171 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
172 unsigned int cpu_idx
= cpu_for_irq(intc
, d
);
174 intc
->cpus
[cpu_idx
]->enable_cache
[word
] &= ~mask
;
175 __raw_writel(intc
->cpus
[cpu_idx
]->enable_cache
[word
],
176 intc
->cpus
[cpu_idx
]->map_base
+ reg_enable(intc
, word
));
179 static void bcm6345_l1_unmask(struct irq_data
*d
)
181 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
184 raw_spin_lock_irqsave(&intc
->lock
, flags
);
185 __bcm6345_l1_unmask(d
);
186 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
189 static void bcm6345_l1_mask(struct irq_data
*d
)
191 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
194 raw_spin_lock_irqsave(&intc
->lock
, flags
);
195 __bcm6345_l1_mask(d
);
196 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
199 static int bcm6345_l1_set_affinity(struct irq_data
*d
,
200 const struct cpumask
*dest
,
203 struct bcm6345_l1_chip
*intc
= irq_data_get_irq_chip_data(d
);
204 u32 word
= d
->hwirq
/ IRQS_PER_WORD
;
205 u32 mask
= BIT(d
->hwirq
% IRQS_PER_WORD
);
206 unsigned int old_cpu
= cpu_for_irq(intc
, d
);
207 unsigned int new_cpu
;
208 struct cpumask valid
;
212 if (!cpumask_and(&valid
, &intc
->cpumask
, dest
))
215 new_cpu
= cpumask_any_and(&valid
, cpu_online_mask
);
216 if (new_cpu
>= nr_cpu_ids
)
219 dest
= cpumask_of(new_cpu
);
221 raw_spin_lock_irqsave(&intc
->lock
, flags
);
222 if (old_cpu
!= new_cpu
) {
223 enabled
= intc
->cpus
[old_cpu
]->enable_cache
[word
] & mask
;
225 __bcm6345_l1_mask(d
);
226 cpumask_copy(irq_data_get_affinity_mask(d
), dest
);
228 __bcm6345_l1_unmask(d
);
230 cpumask_copy(irq_data_get_affinity_mask(d
), dest
);
232 raw_spin_unlock_irqrestore(&intc
->lock
, flags
);
234 return IRQ_SET_MASK_OK_NOCOPY
;
237 static int __init
bcm6345_l1_init_one(struct device_node
*dn
,
239 struct bcm6345_l1_chip
*intc
)
243 struct bcm6345_l1_cpu
*cpu
;
244 unsigned int i
, n_words
;
246 if (of_address_to_resource(dn
, idx
, &res
))
248 sz
= resource_size(&res
);
249 n_words
= sz
/ REG_BYTES_PER_IRQ_WORD
;
252 intc
->n_words
= n_words
;
253 else if (intc
->n_words
!= n_words
)
256 cpu
= intc
->cpus
[idx
] = kzalloc(sizeof(*cpu
) + n_words
* sizeof(u32
),
261 cpu
->map_base
= ioremap(res
.start
, sz
);
265 for (i
= 0; i
< n_words
; i
++) {
266 cpu
->enable_cache
[i
] = 0;
267 __raw_writel(0, cpu
->map_base
+ reg_enable(intc
, i
));
270 cpu
->parent_irq
= irq_of_parse_and_map(dn
, idx
);
271 if (!cpu
->parent_irq
) {
272 pr_err("failed to map parent interrupt %d\n", cpu
->parent_irq
);
275 irq_set_chained_handler_and_data(cpu
->parent_irq
,
276 bcm6345_l1_irq_handle
, intc
);
281 static struct irq_chip bcm6345_l1_irq_chip
= {
282 .name
= "bcm6345-l1",
283 .irq_mask
= bcm6345_l1_mask
,
284 .irq_unmask
= bcm6345_l1_unmask
,
285 .irq_set_affinity
= bcm6345_l1_set_affinity
,
288 static int bcm6345_l1_map(struct irq_domain
*d
, unsigned int virq
,
289 irq_hw_number_t hw_irq
)
291 irq_set_chip_and_handler(virq
,
292 &bcm6345_l1_irq_chip
, handle_percpu_irq
);
293 irq_set_chip_data(virq
, d
->host_data
);
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
);