diff options
author | Bartosz Golaszewski <bgolaszewski@baylibre.com> | 2019-02-14 15:52:16 +0100 |
---|---|---|
committer | Sekhar Nori <nsekhar@ti.com> | 2019-02-19 15:32:17 +0100 |
commit | 0145beed9d2603870509e0701bc77c86c386fc02 (patch) | |
tree | 221f4e89f311ed5cb5d5819175c49dc69734caac /drivers/irqchip | |
parent | ARM: davinci: aintc: remove unnecessary includes (diff) | |
download | linux-0145beed9d2603870509e0701bc77c86c386fc02.tar.xz linux-0145beed9d2603870509e0701bc77c86c386fc02.zip |
irqchip: davinci-aintc: move the driver to drivers/irqchip
The aintc driver has now been cleaned up. Move it to drivers/irqchip
where it belongs. There's no device-tree support for any dm* board so
there's no IRQCHIP_OF_DECLARE() - there's only the exported init
function called from machine code.
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: David Lechner <david@lechnology.com>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/Kconfig | 5 | ||||
-rw-r--r-- | drivers/irqchip/Makefile | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-davinci-aintc.c | 163 |
3 files changed, 169 insertions, 0 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 3d1e60779078..ea0eb82bf1d2 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -129,6 +129,11 @@ config BRCMSTB_L2_IRQ select GENERIC_IRQ_CHIP select IRQ_DOMAIN +config DAVINCI_AINTC + bool + select GENERIC_IRQ_CHIP + select IRQ_DOMAIN + config DW_APB_ICTL bool select GENERIC_IRQ_CHIP diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index c93713d24b86..623e0ec5f9d0 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ATH79) += irq-ath79-cpu.o obj-$(CONFIG_ATH79) += irq-ath79-misc.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o +obj-$(CONFIG_DAVINCI_AINTC) += irq-davinci-aintc.o obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o obj-$(CONFIG_FARADAY_FTINTC010) += irq-ftintc010.o obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o diff --git a/drivers/irqchip/irq-davinci-aintc.c b/drivers/irqchip/irq-davinci-aintc.c new file mode 100644 index 000000000000..810ccc4fe476 --- /dev/null +++ b/drivers/irqchip/irq-davinci-aintc.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// +// Copyright (C) 2006, 2019 Texas Instruments. +// +// Interrupt handler for DaVinci boards. + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/irqchip/irq-davinci-aintc.h> +#include <linux/io.h> +#include <linux/irqdomain.h> + +#include <asm/exception.h> + +#define DAVINCI_AINTC_FIQ_REG0 0x00 +#define DAVINCI_AINTC_FIQ_REG1 0x04 +#define DAVINCI_AINTC_IRQ_REG0 0x08 +#define DAVINCI_AINTC_IRQ_REG1 0x0c +#define DAVINCI_AINTC_IRQ_IRQENTRY 0x14 +#define DAVINCI_AINTC_IRQ_ENT_REG0 0x18 +#define DAVINCI_AINTC_IRQ_ENT_REG1 0x1c +#define DAVINCI_AINTC_IRQ_INCTL_REG 0x20 +#define DAVINCI_AINTC_IRQ_EABASE_REG 0x24 +#define DAVINCI_AINTC_IRQ_INTPRI0_REG 0x30 +#define DAVINCI_AINTC_IRQ_INTPRI7_REG 0x4c + +static void __iomem *davinci_aintc_base; +static struct irq_domain *davinci_aintc_irq_domain; + +static inline void davinci_aintc_writel(unsigned long value, int offset) +{ + writel_relaxed(value, davinci_aintc_base + offset); +} + +static inline unsigned long davinci_aintc_readl(int offset) +{ + return readl_relaxed(davinci_aintc_base + offset); +} + +static __init void +davinci_aintc_setup_gc(void __iomem *base, + unsigned int irq_start, unsigned int num) +{ + struct irq_chip_generic *gc; + struct irq_chip_type *ct; + + gc = irq_get_domain_generic_chip(davinci_aintc_irq_domain, irq_start); + gc->reg_base = base; + gc->irq_base = irq_start; + + ct = gc->chip_types; + ct->chip.irq_ack = irq_gc_ack_set_bit; + ct->chip.irq_mask = irq_gc_mask_clr_bit; + ct->chip.irq_unmask = irq_gc_mask_set_bit; + + ct->regs.ack = DAVINCI_AINTC_IRQ_REG0; + ct->regs.mask = DAVINCI_AINTC_IRQ_ENT_REG0; + irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, + IRQ_NOREQUEST | IRQ_NOPROBE, 0); +} + +static asmlinkage void __exception_irq_entry +davinci_aintc_handle_irq(struct pt_regs *regs) +{ + int irqnr = davinci_aintc_readl(DAVINCI_AINTC_IRQ_IRQENTRY); + + /* + * Use the formula for entry vector index generation from section + * 8.3.3 of the manual. + */ + irqnr >>= 2; + irqnr -= 1; + + handle_domain_irq(davinci_aintc_irq_domain, irqnr, regs); +} + +/* ARM Interrupt Controller Initialization */ +void __init davinci_aintc_init(const struct davinci_aintc_config *config) +{ + unsigned int irq_off, reg_off, prio, shift; + void __iomem *req; + int ret, irq_base; + const u8 *prios; + + req = request_mem_region(config->reg.start, + resource_size(&config->reg), + "davinci-cp-intc"); + if (!req) { + pr_err("%s: register range busy\n", __func__); + return; + } + + davinci_aintc_base = ioremap(config->reg.start, + resource_size(&config->reg)); + if (!davinci_aintc_base) { + pr_err("%s: unable to ioremap register range\n", __func__); + return; + } + + /* Clear all interrupt requests */ + davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0); + davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1); + davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0); + davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1); + + /* Disable all interrupts */ + davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG0); + davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_ENT_REG1); + + /* Interrupts disabled immediately, IRQ entry reflects all */ + davinci_aintc_writel(0x0, DAVINCI_AINTC_IRQ_INCTL_REG); + + /* we don't use the hardware vector table, just its entry addresses */ + davinci_aintc_writel(0, DAVINCI_AINTC_IRQ_EABASE_REG); + + /* Clear all interrupt requests */ + davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG0); + davinci_aintc_writel(~0x0, DAVINCI_AINTC_FIQ_REG1); + davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG0); + davinci_aintc_writel(~0x0, DAVINCI_AINTC_IRQ_REG1); + + prios = config->prios; + for (reg_off = DAVINCI_AINTC_IRQ_INTPRI0_REG; + reg_off <= DAVINCI_AINTC_IRQ_INTPRI7_REG; reg_off += 4) { + for (shift = 0, prio = 0; shift < 32; shift += 4, prios++) + prio |= (*prios & 0x07) << shift; + davinci_aintc_writel(prio, reg_off); + } + + irq_base = irq_alloc_descs(-1, 0, config->num_irqs, 0); + if (irq_base < 0) { + pr_err("%s: unable to allocate interrupt descriptors: %d\n", + __func__, irq_base); + return; + } + + davinci_aintc_irq_domain = irq_domain_add_legacy(NULL, + config->num_irqs, irq_base, 0, + &irq_domain_simple_ops, NULL); + if (!davinci_aintc_irq_domain) { + pr_err("%s: unable to create interrupt domain\n", __func__); + return; + } + + ret = irq_alloc_domain_generic_chips(davinci_aintc_irq_domain, 32, 1, + "AINTC", handle_edge_irq, + IRQ_NOREQUEST | IRQ_NOPROBE, 0, 0); + if (ret) { + pr_err("%s: unable to allocate generic irq chips for domain\n", + __func__); + return; + } + + for (irq_off = 0, reg_off = 0; + irq_off < config->num_irqs; + irq_off += 32, reg_off += 0x04) + davinci_aintc_setup_gc(davinci_aintc_base + reg_off, + irq_base + irq_off, 32); + + set_handle_irq(davinci_aintc_handle_irq); +} |