drivers/irqchip/irq-orion.c

Source file repositories/reference/linux-study-clean/drivers/irqchip/irq-orion.c

File Facts

System
Linux kernel
Corpus path
drivers/irqchip/irq-orion.c
Extension
.c
Size
5804 bytes
Lines
206
Domain
Driver Families
Bucket
drivers/irqchip
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

while (stat) {
			u32 hwirq = __fls(stat);
			generic_handle_domain_irq(orion_irq_domain,
						  gc->irq_base + hwirq);
			stat &= ~(1 << hwirq);
		}
	}
}

static int __init orion_irq_init(struct device_node *np,
				 struct device_node *parent)
{
	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
	int n, ret, base, num_chips = 0;
	struct resource r;

	/* count number of irq chips by valid reg addresses */
	num_chips = of_address_count(np);

	orion_irq_domain = irq_domain_create_linear(of_fwnode_handle(np),
				num_chips * ORION_IRQS_PER_CHIP,
				&irq_generic_chip_ops, NULL);
	if (!orion_irq_domain)
		panic("%pOFn: unable to add irq domain\n", np);

	ret = irq_alloc_domain_generic_chips(orion_irq_domain,
				ORION_IRQS_PER_CHIP, 1, np->full_name,
				handle_level_irq, clr, 0,
				IRQ_GC_INIT_MASK_CACHE);
	if (ret)
		panic("%pOFn: unable to alloc irq domain gc\n", np);

	for (n = 0, base = 0; n < num_chips; n++, base += ORION_IRQS_PER_CHIP) {
		struct irq_chip_generic *gc =
			irq_get_domain_generic_chip(orion_irq_domain, base);

		of_address_to_resource(np, n, &r);

		if (!request_mem_region(r.start, resource_size(&r), np->name))
			panic("%pOFn: unable to request mem region %d",
			      np, n);

		gc->reg_base = ioremap(r.start, resource_size(&r));
		if (!gc->reg_base)
			panic("%pOFn: unable to map resource %d", np, n);

		gc->chip_types[0].regs.mask = ORION_IRQ_MASK;
		gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
		gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;

		/* mask all interrupts */
		writel(0, gc->reg_base + ORION_IRQ_MASK);
	}

	set_handle_irq(orion_handle_irq);
	return 0;
}
IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init);

/*
 * Orion SoC bridge interrupt controller
 */
#define ORION_BRIDGE_IRQ_CAUSE	0x00
#define ORION_BRIDGE_IRQ_MASK	0x04

static void orion_bridge_irq_handler(struct irq_desc *desc)
{
	struct irq_domain *d = irq_desc_get_handler_data(desc);

	struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0);
	u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) &
		   gc->mask_cache;

	while (stat) {
		u32 hwirq = __fls(stat);

		generic_handle_domain_irq(d, gc->irq_base + hwirq);
		stat &= ~(1 << hwirq);
	}
}

/*
 * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register.
 * To avoid interrupt events on stale irqs, we clear them before unmask.
 */
static unsigned int orion_bridge_irq_startup(struct irq_data *d)
{
	struct irq_chip_type *ct = irq_data_get_chip_type(d);

	ct->chip.irq_ack(d);

Annotation

Implementation Notes