1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Broadcom BCM7038 style Level 1 interrupt controller driver
4 *
5 * Copyright (C) 2014 Broadcom Corporation
6 * Author: Kevin Cernekee
7 */
8
9#define pr_fmt(fmt)	KBUILD_MODNAME	": " fmt
10
11#include <linux/bitops.h>
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/io.h>
16#include <linux/ioport.h>
17#include <linux/irq.h>
18#include <linux/irqdomain.h>
19#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_irq.h>
22#include <linux/of_address.h>
23#include <linux/platform_device.h>
24#include <linux/slab.h>
25#include <linux/smp.h>
26#include <linux/types.h>
27#include <linux/irqchip.h>
28#include <linux/irqchip/chained_irq.h>
29#include <linux/syscore_ops.h>
30
31#define IRQS_PER_WORD		32
32#define REG_BYTES_PER_IRQ_WORD	(sizeof(u32) * 4)
33#define MAX_WORDS		8
34
35struct bcm7038_l1_cpu;
36
37struct bcm7038_l1_chip {
38	raw_spinlock_t		lock;
39	unsigned int		n_words;
40	struct irq_domain	*domain;
41	struct bcm7038_l1_cpu	*cpus[NR_CPUS];
42#ifdef CONFIG_PM_SLEEP
43	struct list_head	list;
44	u32			wake_mask[MAX_WORDS];
45#endif
46	u32			irq_fwd_mask[MAX_WORDS];
47	u8			affinity[MAX_WORDS * IRQS_PER_WORD];
48};
49
50struct bcm7038_l1_cpu {
51	void __iomem		*map_base;
52	u32			mask_cache[];
53};
54
55/*
56 * STATUS/MASK_STATUS/MASK_SET/MASK_CLEAR are packed one right after another:
57 *
58 * 7038:
59 *   0x1000_1400: W0_STATUS
60 *   0x1000_1404: W1_STATUS
61 *   0x1000_1408: W0_MASK_STATUS
62 *   0x1000_140c: W1_MASK_STATUS
63 *   0x1000_1410: W0_MASK_SET
64 *   0x1000_1414: W1_MASK_SET
65 *   0x1000_1418: W0_MASK_CLEAR
66 *   0x1000_141c: W1_MASK_CLEAR
67 *
68 * 7445:
69 *   0xf03e_1500: W0_STATUS
70 *   0xf03e_1504: W1_STATUS
71 *   0xf03e_1508: W2_STATUS
72 *   0xf03e_150c: W3_STATUS
73 *   0xf03e_1510: W4_STATUS
74 *   0xf03e_1514: W0_MASK_STATUS
75 *   0xf03e_1518: W1_MASK_STATUS
76 *   [...]
77 */
78
79static inline unsigned int reg_status(struct bcm7038_l1_chip *intc,
80				      unsigned int word)
81{
82	return (0 * intc->n_words + word) * sizeof(u32);
83}
84
85static inline unsigned int reg_mask_status(struct bcm7038_l1_chip *intc,
86					   unsigned int word)
87{
88	return (1 * intc->n_words + word) * sizeof(u32);
89}
90
91static inline unsigned int reg_mask_set(struct bcm7038_l1_chip *intc,
92					unsigned int word)
93{
94	return (2 * intc->n_words + word) * sizeof(u32);
95}
96
97static inline unsigned int reg_mask_clr(struct bcm7038_l1_chip *intc,
98					unsigned int word)
99{
100	return (3 * intc->n_words + word) * sizeof(u32);
101}
102
103static inline u32 l1_readl(void __iomem *reg)
104{
105	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
106		return ioread32be(reg);
107	else
108		return readl(reg);
109}
110
111static inline void l1_writel(u32 val, void __iomem *reg)
112{
113	if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
114		iowrite32be(val, reg);
115	else
116		writel(val, reg);
117}
118
119static void bcm7038_l1_irq_handle(struct irq_desc *desc)
120{
121	struct bcm7038_l1_chip *intc = irq_desc_get_handler_data(desc);
122	struct bcm7038_l1_cpu *cpu;
123	struct irq_chip *chip = irq_desc_get_chip(desc);
124	unsigned int idx;
125
126#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
127	cpu = intc->cpus[cpu_logical_map(smp_processor_id())];
128#else
129	cpu = intc->cpus[0];
130#endif
131
132	chained_irq_enter(chip, desc);
133
134	for (idx = 0; idx < intc->n_words; idx++) {
135		int base = idx * IRQS_PER_WORD;
136		unsigned long pending, flags;
137		int hwirq;
138
139		raw_spin_lock_irqsave(&intc->lock, flags);
140		pending = l1_readl(cpu->map_base + reg_status(intc, idx)) &
141			  ~cpu->mask_cache[idx];
142		raw_spin_unlock_irqrestore(&intc->lock, flags);
143
144		for_each_set_bit(hwirq, &pending, IRQS_PER_WORD)
145			generic_handle_domain_irq(intc->domain, base + hwirq);
146	}
147
148	chained_irq_exit(chip, desc);
149}
150
151static void __bcm7038_l1_unmask(struct irq_data *d, unsigned int cpu_idx)
152{
153	struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
154	u32 word = d->hwirq / IRQS_PER_WORD;
155	u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
156
157	intc->cpus[cpu_idx]->mask_cache[word] &= ~mask;
158	l1_writel(mask, intc->cpus[cpu_idx]->map_base +
159			reg_mask_clr(intc, word));
160}
161
162static void __bcm7038_l1_mask(struct irq_data *d, unsigned int cpu_idx)
163{
164	struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
165	u32 word = d->hwirq / IRQS_PER_WORD;
166	u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
167
168	intc->cpus[cpu_idx]->mask_cache[word] |= mask;
169	l1_writel(mask, intc->cpus[cpu_idx]->map_base +
170			reg_mask_set(intc, word));
171}
172
173static void bcm7038_l1_unmask(struct irq_data *d)
174{
175	struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
176	unsigned long flags;
177
178	raw_spin_lock_irqsave(&intc->lock, flags);
179	__bcm7038_l1_unmask(d, intc->affinity[d->hwirq]);
180	raw_spin_unlock_irqrestore(&intc->lock, flags);
181}
182
183static void bcm7038_l1_mask(struct irq_data *d)
184{
185	struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
186	unsigned long flags;
187
188	raw_spin_lock_irqsave(&intc->lock, flags);
189	__bcm7038_l1_mask(d, intc->affinity[d->hwirq]);
190	raw_spin_unlock_irqrestore(&intc->lock, flags);
191}
192
193#if defined(CONFIG_MIPS) && defined(CONFIG_SMP)
194static int bcm7038_l1_set_affinity(struct irq_data *d,
195				   const struct cpumask *dest,
196				   bool force)
197{
198	struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
199	unsigned long flags;
200	irq_hw_number_t hw = d->hwirq;
201	u32 word = hw / IRQS_PER_WORD;
202	u32 mask = BIT(hw % IRQS_PER_WORD);
203	unsigned int first_cpu = cpumask_any_and(dest, cpu_online_mask);
204	bool was_disabled;
205
206	raw_spin_lock_irqsave(&intc->lock, flags);
207
208	was_disabled = !!(intc->cpus[intc->affinity[hw]]->mask_cache[word] &
209			  mask);
210	__bcm7038_l1_mask(d, intc->affinity[hw]);
211	intc->affinity[hw] = first_cpu;
212	if (!was_disabled)
213		__bcm7038_l1_unmask(d, first_cpu);
214
215	raw_spin_unlock_irqrestore(&intc->lock, flags);
216	irq_data_update_effective_affinity(d, cpumask_of(first_cpu));
217
218	return 0;
219}
220#endif
221
222static int __init bcm7038_l1_init_one(struct device_node *dn,
223				      unsigned int idx,
224				      struct bcm7038_l1_chip *intc)
225{
226	struct resource res;
227	resource_size_t sz;
228	struct bcm7038_l1_cpu *cpu;
229	unsigned int i, n_words, parent_irq;
230	int ret;
231
232	if (of_address_to_resource(dn, idx, &res))
233		return -EINVAL;
234	sz = resource_size(&res);
235	n_words = sz / REG_BYTES_PER_IRQ_WORD;
236
237	if (n_words > MAX_WORDS)
238		return -EINVAL;
239	else if (!intc->n_words)
240		intc->n_words = n_words;
241	else if (intc->n_words != n_words)
242		return -EINVAL;
243
244	ret = of_property_read_u32_array(dn , "brcm,int-fwd-mask",
245					 intc->irq_fwd_mask, n_words);
246	if (ret != 0 && ret != -EINVAL) {
247		/* property exists but has the wrong number of words */
248		pr_err("invalid brcm,int-fwd-mask property\n");
249		return -EINVAL;
250	}
251
252	cpu = intc->cpus[idx] = kzalloc(struct_size(cpu, mask_cache, n_words),
253					GFP_KERNEL);
254	if (!cpu)
255		return -ENOMEM;
256
257	cpu->map_base = ioremap(res.start, sz);
258	if (!cpu->map_base)
259		return -ENOMEM;
260
261	for (i = 0; i < n_words; i++) {
262		l1_writel(~intc->irq_fwd_mask[i],
263			  cpu->map_base + reg_mask_set(intc, i));
264		l1_writel(intc->irq_fwd_mask[i],
265			  cpu->map_base + reg_mask_clr(intc, i));
266		cpu->mask_cache[i] = ~intc->irq_fwd_mask[i];
267	}
268
269	parent_irq = irq_of_parse_and_map(dn, idx);
270	if (!parent_irq) {
271		pr_err("failed to map parent interrupt %d\n", parent_irq);
272		return -EINVAL;
273	}
274
275	if (of_property_read_bool(dn, "brcm,irq-can-wake"))
276		enable_irq_wake(parent_irq);
277
278	irq_set_chained_handler_and_data(parent_irq, bcm7038_l1_irq_handle,
279					 intc);
280
281	return 0;
282}
283
284#ifdef CONFIG_PM_SLEEP
285/*
286 * We keep a list of bcm7038_l1_chip used for suspend/resume. This hack is
287 * used because the struct chip_type suspend/resume hooks are not called
288 * unless chip_type is hooked onto a generic_chip. Since this driver does
289 * not use generic_chip, we need to manually hook our resume/suspend to
290 * syscore_ops.
291 */
292static LIST_HEAD(bcm7038_l1_intcs_list);
293static DEFINE_RAW_SPINLOCK(bcm7038_l1_intcs_lock);
294
295static int bcm7038_l1_suspend(void)
296{
297	struct bcm7038_l1_chip *intc;
298	int boot_cpu, word;
299	u32 val;
300
301	/* Wakeup interrupt should only come from the boot cpu */
302#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
303	boot_cpu = cpu_logical_map(0);
304#else
305	boot_cpu = 0;
306#endif
307
308	list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
309		for (word = 0; word < intc->n_words; word++) {
310			val = intc->wake_mask[word] | intc->irq_fwd_mask[word];
311			l1_writel(~val,
312				intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
313			l1_writel(val,
314				intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
315		}
316	}
317
318	return 0;
319}
320
321static void bcm7038_l1_resume(void)
322{
323	struct bcm7038_l1_chip *intc;
324	int boot_cpu, word;
325
326#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
327	boot_cpu = cpu_logical_map(0);
328#else
329	boot_cpu = 0;
330#endif
331
332	list_for_each_entry(intc, &bcm7038_l1_intcs_list, list) {
333		for (word = 0; word < intc->n_words; word++) {
334			l1_writel(intc->cpus[boot_cpu]->mask_cache[word],
335				intc->cpus[boot_cpu]->map_base + reg_mask_set(intc, word));
336			l1_writel(~intc->cpus[boot_cpu]->mask_cache[word],
337				intc->cpus[boot_cpu]->map_base + reg_mask_clr(intc, word));
338		}
339	}
340}
341
342static struct syscore_ops bcm7038_l1_syscore_ops = {
343	.suspend	= bcm7038_l1_suspend,
344	.resume		= bcm7038_l1_resume,
345};
346
347static int bcm7038_l1_set_wake(struct irq_data *d, unsigned int on)
348{
349	struct bcm7038_l1_chip *intc = irq_data_get_irq_chip_data(d);
350	unsigned long flags;
351	u32 word = d->hwirq / IRQS_PER_WORD;
352	u32 mask = BIT(d->hwirq % IRQS_PER_WORD);
353
354	raw_spin_lock_irqsave(&intc->lock, flags);
355	if (on)
356		intc->wake_mask[word] |= mask;
357	else
358		intc->wake_mask[word] &= ~mask;
359	raw_spin_unlock_irqrestore(&intc->lock, flags);
360
361	return 0;
362}
363#endif
364
365static struct irq_chip bcm7038_l1_irq_chip = {
366	.name			= "bcm7038-l1",
367	.irq_mask		= bcm7038_l1_mask,
368	.irq_unmask		= bcm7038_l1_unmask,
369#if defined(CONFIG_SMP) && defined(CONFIG_MIPS)
370	.irq_set_affinity	= bcm7038_l1_set_affinity,
371#endif
372#ifdef CONFIG_PM_SLEEP
373	.irq_set_wake		= bcm7038_l1_set_wake,
374#endif
375};
376
377static int bcm7038_l1_map(struct irq_domain *d, unsigned int virq,
378			  irq_hw_number_t hw_irq)
379{
380	struct bcm7038_l1_chip *intc = d->host_data;
381	u32 mask = BIT(hw_irq % IRQS_PER_WORD);
382	u32 word = hw_irq / IRQS_PER_WORD;
383
384	if (intc->irq_fwd_mask[word] & mask)
385		return -EPERM;
386
387	irq_set_chip_and_handler(virq, &bcm7038_l1_irq_chip, handle_level_irq);
388	irq_set_chip_data(virq, d->host_data);
389	irqd_set_single_target(irq_get_irq_data(virq));
390	return 0;
391}
392
393static const struct irq_domain_ops bcm7038_l1_domain_ops = {
394	.xlate			= irq_domain_xlate_onecell,
395	.map			= bcm7038_l1_map,
396};
397
398static int __init bcm7038_l1_of_init(struct device_node *dn,
399			      struct device_node *parent)
400{
401	struct bcm7038_l1_chip *intc;
402	int idx, ret;
403
404	intc = kzalloc(sizeof(*intc), GFP_KERNEL);
405	if (!intc)
406		return -ENOMEM;
407
408	raw_spin_lock_init(&intc->lock);
409	for_each_possible_cpu(idx) {
410		ret = bcm7038_l1_init_one(dn, idx, intc);
411		if (ret < 0) {
412			if (idx)
413				break;
414			pr_err("failed to remap intc L1 registers\n");
415			goto out_free;
416		}
417	}
418
419	intc->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * intc->n_words,
420					     &bcm7038_l1_domain_ops,
421					     intc);
422	if (!intc->domain) {
423		ret = -ENOMEM;
424		goto out_unmap;
425	}
426
427#ifdef CONFIG_PM_SLEEP
428	/* Add bcm7038_l1_chip into a list */
429	raw_spin_lock(&bcm7038_l1_intcs_lock);
430	list_add_tail(&intc->list, &bcm7038_l1_intcs_list);
431	raw_spin_unlock(&bcm7038_l1_intcs_lock);
432
433	if (list_is_singular(&bcm7038_l1_intcs_list))
434		register_syscore_ops(&bcm7038_l1_syscore_ops);
435#endif
436
437	pr_info("registered BCM7038 L1 intc (%pOF, IRQs: %d)\n",
438		dn, IRQS_PER_WORD * intc->n_words);
439
440	return 0;
441
442out_unmap:
443	for_each_possible_cpu(idx) {
444		struct bcm7038_l1_cpu *cpu = intc->cpus[idx];
445
446		if (cpu) {
447			if (cpu->map_base)
448				iounmap(cpu->map_base);
449			kfree(cpu);
450		}
451	}
452out_free:
453	kfree(intc);
454	return ret;
455}
456
457IRQCHIP_PLATFORM_DRIVER_BEGIN(bcm7038_l1)
458IRQCHIP_MATCH("brcm,bcm7038-l1-intc", bcm7038_l1_of_init)
459IRQCHIP_PLATFORM_DRIVER_END(bcm7038_l1)
460MODULE_DESCRIPTION("Broadcom STB 7038-style L1/L2 interrupt controller");
461MODULE_LICENSE("GPL v2");
462