Lines Matching +full:parent +full:- +full:interrupt +full:- +full:base

1 // SPDX-License-Identifier: GPL-2.0-only
3 * Generic Broadcom Set Top Box Level 2 Interrupt controller driver
5 * Copyright (C) 2014-2024 Broadcom
18 #include <linux/interrupt.h>
34 /* Register offsets in the L2 latched interrupt controller */
44 /* Register offsets in the L2 level interrupt controller */
48 .cpu_clear = -1, /* Register not present */
65 * brcmstb_l2_mask_and_ack - Mask and ack pending interrupt
69 * register and pending interrupt is acknowledged by setting a bit.
81 u32 mask = d->mask; in brcmstb_l2_mask_and_ack()
84 irq_reg_writel(gc, mask, ct->regs.disable); in brcmstb_l2_mask_and_ack()
85 *ct->mask_cache &= ~mask; in brcmstb_l2_mask_and_ack()
86 irq_reg_writel(gc, mask, ct->regs.ack); in brcmstb_l2_mask_and_ack()
99 status = irq_reg_readl(b->gc, b->status_offset) & in brcmstb_l2_intc_irq_handle()
100 ~(irq_reg_readl(b->gc, b->mask_offset)); in brcmstb_l2_intc_irq_handle()
103 raw_spin_lock(&desc->lock); in brcmstb_l2_intc_irq_handle()
105 raw_spin_unlock(&desc->lock); in brcmstb_l2_intc_irq_handle()
110 irq = ffs(status) - 1; in brcmstb_l2_intc_irq_handle()
112 generic_handle_domain_irq(b->domain, irq); in brcmstb_l2_intc_irq_handle()
115 /* Don't ack parent before all device writes are done */ in brcmstb_l2_intc_irq_handle()
125 struct brcmstb_l2_intc_data *b = gc->private; in __brcmstb_l2_intc_suspend()
131 b->saved_mask = irq_reg_readl(gc, ct->regs.mask); in __brcmstb_l2_intc_suspend()
133 if (b->can_wake) { in __brcmstb_l2_intc_suspend()
135 irq_reg_writel(gc, ~gc->wake_active, ct->regs.disable); in __brcmstb_l2_intc_suspend()
136 irq_reg_writel(gc, gc->wake_active, ct->regs.enable); in __brcmstb_l2_intc_suspend()
155 struct brcmstb_l2_intc_data *b = gc->private; in brcmstb_l2_intc_resume()
159 if (ct->chip.irq_ack) { in brcmstb_l2_intc_resume()
160 /* Clear unmasked non-wakeup interrupts */ in brcmstb_l2_intc_resume()
161 irq_reg_writel(gc, ~b->saved_mask & ~gc->wake_active, in brcmstb_l2_intc_resume()
162 ct->regs.ack); in brcmstb_l2_intc_resume()
166 irq_reg_writel(gc, b->saved_mask, ct->regs.disable); in brcmstb_l2_intc_resume()
167 irq_reg_writel(gc, ~b->saved_mask, ct->regs.enable); in brcmstb_l2_intc_resume()
172 struct device_node *parent, in brcmstb_l2_intc_of_init() argument
183 void __iomem *base; in brcmstb_l2_intc_of_init() local
187 return -ENOMEM; in brcmstb_l2_intc_of_init()
189 base = of_iomap(np, 0); in brcmstb_l2_intc_of_init()
190 if (!base) { in brcmstb_l2_intc_of_init()
192 ret = -ENOMEM; in brcmstb_l2_intc_of_init()
197 writel(0xffffffff, base + init_params->cpu_mask_set); in brcmstb_l2_intc_of_init()
200 data->can_wake = of_property_read_bool(np, "brcm,irq-can-wake"); in brcmstb_l2_intc_of_init()
201 if (!data->can_wake && (init_params->cpu_clear >= 0)) in brcmstb_l2_intc_of_init()
202 writel(0xffffffff, base + init_params->cpu_clear); in brcmstb_l2_intc_of_init()
206 pr_err("failed to find parent interrupt\n"); in brcmstb_l2_intc_of_init()
207 ret = -EINVAL; in brcmstb_l2_intc_of_init()
211 data->domain = irq_domain_add_linear(np, 32, in brcmstb_l2_intc_of_init()
213 if (!data->domain) { in brcmstb_l2_intc_of_init()
214 ret = -ENOMEM; in brcmstb_l2_intc_of_init()
219 * peripheral registers for CPU-native byte order. in brcmstb_l2_intc_of_init()
225 if (init_params->handler == handle_level_irq) in brcmstb_l2_intc_of_init()
229 ret = irq_alloc_domain_generic_chips(data->domain, 32, 1, in brcmstb_l2_intc_of_init()
230 np->full_name, init_params->handler, clr, set, flags); in brcmstb_l2_intc_of_init()
240 data->gc = irq_get_domain_generic_chip(data->domain, 0); in brcmstb_l2_intc_of_init()
241 data->gc->reg_base = base; in brcmstb_l2_intc_of_init()
242 data->gc->private = data; in brcmstb_l2_intc_of_init()
243 data->status_offset = init_params->cpu_status; in brcmstb_l2_intc_of_init()
244 data->mask_offset = init_params->cpu_mask_status; in brcmstb_l2_intc_of_init()
246 ct = data->gc->chip_types; in brcmstb_l2_intc_of_init()
248 if (init_params->cpu_clear >= 0) { in brcmstb_l2_intc_of_init()
249 ct->regs.ack = init_params->cpu_clear; in brcmstb_l2_intc_of_init()
250 ct->chip.irq_ack = irq_gc_ack_set_bit; in brcmstb_l2_intc_of_init()
251 ct->chip.irq_mask_ack = brcmstb_l2_mask_and_ack; in brcmstb_l2_intc_of_init()
253 /* No Ack - but still slightly more efficient to define this */ in brcmstb_l2_intc_of_init()
254 ct->chip.irq_mask_ack = irq_gc_mask_disable_reg; in brcmstb_l2_intc_of_init()
257 ct->chip.irq_mask = irq_gc_mask_disable_reg; in brcmstb_l2_intc_of_init()
258 ct->regs.disable = init_params->cpu_mask_set; in brcmstb_l2_intc_of_init()
259 ct->regs.mask = init_params->cpu_mask_status; in brcmstb_l2_intc_of_init()
261 ct->chip.irq_unmask = irq_gc_unmask_enable_reg; in brcmstb_l2_intc_of_init()
262 ct->regs.enable = init_params->cpu_mask_clear; in brcmstb_l2_intc_of_init()
264 ct->chip.irq_suspend = brcmstb_l2_intc_suspend; in brcmstb_l2_intc_of_init()
265 ct->chip.irq_resume = brcmstb_l2_intc_resume; in brcmstb_l2_intc_of_init()
266 ct->chip.irq_pm_shutdown = brcmstb_l2_intc_shutdown; in brcmstb_l2_intc_of_init()
268 if (data->can_wake) { in brcmstb_l2_intc_of_init()
272 data->gc->wake_enabled = 0xffffffff; in brcmstb_l2_intc_of_init()
273 ct->chip.irq_set_wake = irq_gc_set_wake; in brcmstb_l2_intc_of_init()
277 pr_info("registered L2 intc (%pOF, parent irq: %d)\n", np, parent_irq); in brcmstb_l2_intc_of_init()
282 irq_domain_remove(data->domain); in brcmstb_l2_intc_of_init()
284 iounmap(base); in brcmstb_l2_intc_of_init()
291 struct device_node *parent) in brcmstb_l2_edge_intc_of_init() argument
293 return brcmstb_l2_intc_of_init(np, parent, &l2_edge_intc_init); in brcmstb_l2_edge_intc_of_init()
297 struct device_node *parent) in brcmstb_l2_lvl_intc_of_init() argument
299 return brcmstb_l2_intc_of_init(np, parent, &l2_lvl_intc_init); in brcmstb_l2_lvl_intc_of_init()
303 IRQCHIP_MATCH("brcm,l2-intc", brcmstb_l2_edge_intc_of_init)
304 IRQCHIP_MATCH("brcm,hif-spi-l2-intc", brcmstb_l2_edge_intc_of_init)
305 IRQCHIP_MATCH("brcm,upg-aux-aon-l2-intc", brcmstb_l2_edge_intc_of_init)
306 IRQCHIP_MATCH("brcm,bcm7271-l2-intc", brcmstb_l2_lvl_intc_of_init)
308 MODULE_DESCRIPTION("Broadcom STB generic L2 interrupt controller");