18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/drivers/irqchip/irq-zevio.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci#include <linux/irq.h>
108c2ecf20Sopenharmony_ci#include <linux/irqchip.h>
118c2ecf20Sopenharmony_ci#include <linux/of.h>
128c2ecf20Sopenharmony_ci#include <linux/of_address.h>
138c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <asm/mach/irq.h>
168c2ecf20Sopenharmony_ci#include <asm/exception.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define IO_STATUS	0x000
198c2ecf20Sopenharmony_ci#define IO_RAW_STATUS	0x004
208c2ecf20Sopenharmony_ci#define IO_ENABLE	0x008
218c2ecf20Sopenharmony_ci#define IO_DISABLE	0x00C
228c2ecf20Sopenharmony_ci#define IO_CURRENT	0x020
238c2ecf20Sopenharmony_ci#define IO_RESET	0x028
248c2ecf20Sopenharmony_ci#define IO_MAX_PRIOTY	0x02C
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define IO_IRQ_BASE	0x000
278c2ecf20Sopenharmony_ci#define IO_FIQ_BASE	0x100
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#define IO_INVERT_SEL	0x200
308c2ecf20Sopenharmony_ci#define IO_STICKY_SEL	0x204
318c2ecf20Sopenharmony_ci#define IO_PRIORITY_SEL	0x300
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define MAX_INTRS	32
348c2ecf20Sopenharmony_ci#define FIQ_START	MAX_INTRS
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic struct irq_domain *zevio_irq_domain;
378c2ecf20Sopenharmony_cistatic void __iomem *zevio_irq_io;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic void zevio_irq_ack(struct irq_data *irqd)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(irqd);
428c2ecf20Sopenharmony_ci	struct irq_chip_regs *regs = &irq_data_get_chip_type(irqd)->regs;
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	readl(gc->reg_base + regs->ack);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int irqnr;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	while (readl(zevio_irq_io + IO_STATUS)) {
528c2ecf20Sopenharmony_ci		irqnr = readl(zevio_irq_io + IO_CURRENT);
538c2ecf20Sopenharmony_ci		handle_domain_irq(zevio_irq_domain, irqnr, regs);
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void __init zevio_init_irq_base(void __iomem *base)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	/* Disable all interrupts */
608c2ecf20Sopenharmony_ci	writel(~0, base + IO_DISABLE);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Accept interrupts of all priorities */
638c2ecf20Sopenharmony_ci	writel(0xF, base + IO_MAX_PRIOTY);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	/* Reset existing interrupts */
668c2ecf20Sopenharmony_ci	readl(base + IO_RESET);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int __init zevio_of_init(struct device_node *node,
708c2ecf20Sopenharmony_ci				struct device_node *parent)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
738c2ecf20Sopenharmony_ci	struct irq_chip_generic *gc;
748c2ecf20Sopenharmony_ci	int ret;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (WARN_ON(zevio_irq_io || zevio_irq_domain))
778c2ecf20Sopenharmony_ci		return -EBUSY;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	zevio_irq_io = of_iomap(node, 0);
808c2ecf20Sopenharmony_ci	BUG_ON(!zevio_irq_io);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	/* Do not invert interrupt status bits */
838c2ecf20Sopenharmony_ci	writel(~0, zevio_irq_io + IO_INVERT_SEL);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	/* Disable sticky interrupts */
868c2ecf20Sopenharmony_ci	writel(0, zevio_irq_io + IO_STICKY_SEL);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	/* We don't use IRQ priorities. Set each IRQ to highest priority. */
898c2ecf20Sopenharmony_ci	memset_io(zevio_irq_io + IO_PRIORITY_SEL, 0, MAX_INTRS * sizeof(u32));
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* Init IRQ and FIQ */
928c2ecf20Sopenharmony_ci	zevio_init_irq_base(zevio_irq_io + IO_IRQ_BASE);
938c2ecf20Sopenharmony_ci	zevio_init_irq_base(zevio_irq_io + IO_FIQ_BASE);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	zevio_irq_domain = irq_domain_add_linear(node, MAX_INTRS,
968c2ecf20Sopenharmony_ci						 &irq_generic_chip_ops, NULL);
978c2ecf20Sopenharmony_ci	BUG_ON(!zevio_irq_domain);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	ret = irq_alloc_domain_generic_chips(zevio_irq_domain, MAX_INTRS, 1,
1008c2ecf20Sopenharmony_ci					     "zevio_intc", handle_level_irq,
1018c2ecf20Sopenharmony_ci					     clr, 0, IRQ_GC_INIT_MASK_CACHE);
1028c2ecf20Sopenharmony_ci	BUG_ON(ret);
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	gc = irq_get_domain_generic_chip(zevio_irq_domain, 0);
1058c2ecf20Sopenharmony_ci	gc->reg_base				= zevio_irq_io;
1068c2ecf20Sopenharmony_ci	gc->chip_types[0].chip.irq_ack		= zevio_irq_ack;
1078c2ecf20Sopenharmony_ci	gc->chip_types[0].chip.irq_mask		= irq_gc_mask_disable_reg;
1088c2ecf20Sopenharmony_ci	gc->chip_types[0].chip.irq_unmask	= irq_gc_unmask_enable_reg;
1098c2ecf20Sopenharmony_ci	gc->chip_types[0].regs.mask		= IO_IRQ_BASE + IO_ENABLE;
1108c2ecf20Sopenharmony_ci	gc->chip_types[0].regs.enable		= IO_IRQ_BASE + IO_ENABLE;
1118c2ecf20Sopenharmony_ci	gc->chip_types[0].regs.disable		= IO_IRQ_BASE + IO_DISABLE;
1128c2ecf20Sopenharmony_ci	gc->chip_types[0].regs.ack		= IO_IRQ_BASE + IO_RESET;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	set_handle_irq(zevio_handle_irq);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	pr_info("TI-NSPIRE classic IRQ controller\n");
1178c2ecf20Sopenharmony_ci	return 0;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciIRQCHIP_DECLARE(zevio_irq, "lsi,zevio-intc", zevio_of_init);
121