diff options
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/Makefile | 2 | ||||
-rw-r--r-- | drivers/irqchip/exynos-combiner.c | 1 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic.c | 39 | ||||
-rw-r--r-- | drivers/irqchip/irq-sun4i.c | 149 | ||||
-rw-r--r-- | drivers/irqchip/irq-sunxi.c | 151 | ||||
-rw-r--r-- | drivers/irqchip/irq-versatile-fpga.c | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-vic.c | 3 |
7 files changed, 181 insertions, 166 deletions
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index b9fceb72905..10ef57f35a6 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -5,7 +5,7 @@ obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o obj-$(CONFIG_ARCH_MXS) += irq-mxs.o obj-$(CONFIG_METAG) += irq-metag-ext.o obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o -obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi.o +obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 04d86a9803f..6a520135150 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/irqdomain.h> +#include <linux/irqchip/chained_irq.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <asm/mach/irq.h> diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index a32e0d5aa45..1760ceb68b7 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -28,6 +28,7 @@ #include <linux/module.h> #include <linux/list.h> #include <linux/smp.h> +#include <linux/cpu.h> #include <linux/cpu_pm.h> #include <linux/cpumask.h> #include <linux/io.h> @@ -38,12 +39,12 @@ #include <linux/interrupt.h> #include <linux/percpu.h> #include <linux/slab.h> +#include <linux/irqchip/chained_irq.h> #include <linux/irqchip/arm-gic.h> #include <asm/irq.h> #include <asm/exception.h> #include <asm/smp_plat.h> -#include <asm/mach/irq.h> #include "irqchip.h" @@ -127,7 +128,7 @@ static inline void gic_set_base_accessor(struct gic_chip_data *data, #else #define gic_data_dist_base(d) ((d)->dist_base.common_base) #define gic_data_cpu_base(d) ((d)->cpu_base.common_base) -#define gic_set_base_accessor(d,f) +#define gic_set_base_accessor(d, f) #endif static inline void __iomem *gic_dist_base(struct irq_data *d) @@ -236,7 +237,8 @@ static int gic_retrigger(struct irq_data *d) if (gic_arch_extn.irq_retrigger) return gic_arch_extn.irq_retrigger(d); - return -ENXIO; + /* the genirq layer expects 0 if we can't retrigger in hardware */ + return 0; } #ifdef CONFIG_SMP @@ -323,7 +325,7 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) cascade_irq = irq_find_mapping(chip_data->domain, gic_irq); if (unlikely(gic_irq < 32 || gic_irq > 1020)) - do_bad_IRQ(cascade_irq, desc); + handle_bad_irq(cascade_irq, desc); else generic_handle_irq(cascade_irq); @@ -699,6 +701,25 @@ static int gic_irq_domain_xlate(struct irq_domain *d, return 0; } +#ifdef CONFIG_SMP +static int __cpuinit gic_secondary_init(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + if (action == CPU_STARTING) + gic_cpu_init(&gic_data[0]); + return NOTIFY_OK; +} + +/* + * Notifier for enabling the GIC CPU interface. Set an arbitrarily high + * priority because the GIC needs to be up before the ARM generic timers. + */ +static struct notifier_block __cpuinitdata gic_cpu_notifier = { + .notifier_call = gic_secondary_init, + .priority = 100, +}; +#endif + const struct irq_domain_ops gic_irq_domain_ops = { .map = gic_irq_domain_map, .xlate = gic_irq_domain_xlate, @@ -789,6 +810,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, #ifdef CONFIG_SMP set_smp_cross_call(gic_raise_softirq); + register_cpu_notifier(&gic_cpu_notifier); #endif set_handle_irq(gic_handle_irq); @@ -799,15 +821,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_pm_init(gic); } -void __cpuinit gic_secondary_init(unsigned int gic_nr) -{ - BUG_ON(gic_nr >= MAX_GIC_NR); - - gic_cpu_init(&gic_data[gic_nr]); -} - #ifdef CONFIG_OF -static int gic_cnt __initdata = 0; +static int gic_cnt __initdata; int __init gic_of_init(struct device_node *node, struct device_node *parent) { diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c new file mode 100644 index 00000000000..b66d4ae0689 --- /dev/null +++ b/drivers/irqchip/irq-sun4i.c @@ -0,0 +1,149 @@ +/* + * Allwinner A1X SoCs IRQ chip driver. + * + * Copyright (C) 2012 Maxime Ripard + * + * Maxime Ripard <maxime.ripard@free-electrons.com> + * + * Based on code from + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Benn Huang <benn@allwinnertech.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#include <asm/exception.h> +#include <asm/mach/irq.h> + +#include "irqchip.h" + +#define SUN4I_IRQ_VECTOR_REG 0x00 +#define SUN4I_IRQ_PROTECTION_REG 0x08 +#define SUN4I_IRQ_NMI_CTRL_REG 0x0c +#define SUN4I_IRQ_PENDING_REG(x) (0x10 + 0x4 * x) +#define SUN4I_IRQ_FIQ_PENDING_REG(x) (0x20 + 0x4 * x) +#define SUN4I_IRQ_ENABLE_REG(x) (0x40 + 0x4 * x) +#define SUN4I_IRQ_MASK_REG(x) (0x50 + 0x4 * x) + +static void __iomem *sun4i_irq_base; +static struct irq_domain *sun4i_irq_domain; + +static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs); + +void sun4i_irq_ack(struct irq_data *irqd) +{ + unsigned int irq = irqd_to_hwirq(irqd); + unsigned int irq_off = irq % 32; + int reg = irq / 32; + u32 val; + + val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); + writel(val | (1 << irq_off), + sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg)); +} + +static void sun4i_irq_mask(struct irq_data *irqd) +{ + unsigned int irq = irqd_to_hwirq(irqd); + unsigned int irq_off = irq % 32; + int reg = irq / 32; + u32 val; + + val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); + writel(val & ~(1 << irq_off), + sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +} + +static void sun4i_irq_unmask(struct irq_data *irqd) +{ + unsigned int irq = irqd_to_hwirq(irqd); + unsigned int irq_off = irq % 32; + int reg = irq / 32; + u32 val; + + val = readl(sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); + writel(val | (1 << irq_off), + sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(reg)); +} + +static struct irq_chip sun4i_irq_chip = { + .name = "sun4i_irq", + .irq_ack = sun4i_irq_ack, + .irq_mask = sun4i_irq_mask, + .irq_unmask = sun4i_irq_unmask, +}; + +static int sun4i_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &sun4i_irq_chip, + handle_level_irq); + set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + + return 0; +} + +static struct irq_domain_ops sun4i_irq_ops = { + .map = sun4i_irq_map, + .xlate = irq_domain_xlate_onecell, +}; + +static int __init sun4i_of_init(struct device_node *node, + struct device_node *parent) +{ + sun4i_irq_base = of_iomap(node, 0); + if (!sun4i_irq_base) + panic("%s: unable to map IC registers\n", + node->full_name); + + /* Disable all interrupts */ + writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(0)); + writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1)); + writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2)); + + /* Mask all the interrupts */ + writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0)); + writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1)); + writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2)); + + /* Clear all the pending interrupts */ + writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)); + writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(1)); + writel(0xffffffff, sun4i_irq_base + SUN4I_IRQ_PENDING_REG(2)); + + /* Enable protection mode */ + writel(0x01, sun4i_irq_base + SUN4I_IRQ_PROTECTION_REG); + + /* Configure the external interrupt source type */ + writel(0x00, sun4i_irq_base + SUN4I_IRQ_NMI_CTRL_REG); + + sun4i_irq_domain = irq_domain_add_linear(node, 3 * 32, + &sun4i_irq_ops, NULL); + if (!sun4i_irq_domain) + panic("%s: unable to create IRQ domain\n", node->full_name); + + set_handle_irq(sun4i_handle_irq); + + return 0; +} +IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-ic", sun4i_of_init); + +static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs) +{ + u32 irq, hwirq; + + hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; + while (hwirq != 0) { + irq = irq_find_mapping(sun4i_irq_domain, hwirq); + handle_IRQ(irq, regs); + hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; + } +} diff --git a/drivers/irqchip/irq-sunxi.c b/drivers/irqchip/irq-sunxi.c deleted file mode 100644 index 10974fa4265..00000000000 --- a/drivers/irqchip/irq-sunxi.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Allwinner A1X SoCs IRQ chip driver. - * - * Copyright (C) 2012 Maxime Ripard - * - * Maxime Ripard <maxime.ripard@free-electrons.com> - * - * Based on code from - * Allwinner Technology Co., Ltd. <www.allwinnertech.com> - * Benn Huang <benn@allwinnertech.com> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> - -#include <linux/irqchip/sunxi.h> - -#define SUNXI_IRQ_VECTOR_REG 0x00 -#define SUNXI_IRQ_PROTECTION_REG 0x08 -#define SUNXI_IRQ_NMI_CTRL_REG 0x0c -#define SUNXI_IRQ_PENDING_REG(x) (0x10 + 0x4 * x) -#define SUNXI_IRQ_FIQ_PENDING_REG(x) (0x20 + 0x4 * x) -#define SUNXI_IRQ_ENABLE_REG(x) (0x40 + 0x4 * x) -#define SUNXI_IRQ_MASK_REG(x) (0x50 + 0x4 * x) - -static void __iomem *sunxi_irq_base; -static struct irq_domain *sunxi_irq_domain; - -void sunxi_irq_ack(struct irq_data *irqd) -{ - unsigned int irq = irqd_to_hwirq(irqd); - unsigned int irq_off = irq % 32; - int reg = irq / 32; - u32 val; - - val = readl(sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg)); - writel(val | (1 << irq_off), - sunxi_irq_base + SUNXI_IRQ_PENDING_REG(reg)); -} - -static void sunxi_irq_mask(struct irq_data *irqd) -{ - unsigned int irq = irqd_to_hwirq(irqd); - unsigned int irq_off = irq % 32; - int reg = irq / 32; - u32 val; - - val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); - writel(val & ~(1 << irq_off), - sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); -} - -static void sunxi_irq_unmask(struct irq_data *irqd) -{ - unsigned int irq = irqd_to_hwirq(irqd); - unsigned int irq_off = irq % 32; - int reg = irq / 32; - u32 val; - - val = readl(sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); - writel(val | (1 << irq_off), - sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(reg)); -} - -static struct irq_chip sunxi_irq_chip = { - .name = "sunxi_irq", - .irq_ack = sunxi_irq_ack, - .irq_mask = sunxi_irq_mask, - .irq_unmask = sunxi_irq_unmask, -}; - -static int sunxi_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - irq_set_chip_and_handler(virq, &sunxi_irq_chip, - handle_level_irq); - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); - - return 0; -} - -static struct irq_domain_ops sunxi_irq_ops = { - .map = sunxi_irq_map, - .xlate = irq_domain_xlate_onecell, -}; - -static int __init sunxi_of_init(struct device_node *node, - struct device_node *parent) -{ - sunxi_irq_base = of_iomap(node, 0); - if (!sunxi_irq_base) - panic("%s: unable to map IC registers\n", - node->full_name); - - /* Disable all interrupts */ - writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(0)); - writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(1)); - writel(0, sunxi_irq_base + SUNXI_IRQ_ENABLE_REG(2)); - - /* Mask all the interrupts */ - writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(0)); - writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(1)); - writel(0, sunxi_irq_base + SUNXI_IRQ_MASK_REG(2)); - - /* Clear all the pending interrupts */ - writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(0)); - writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(1)); - writel(0xffffffff, sunxi_irq_base + SUNXI_IRQ_PENDING_REG(2)); - - /* Enable protection mode */ - writel(0x01, sunxi_irq_base + SUNXI_IRQ_PROTECTION_REG); - - /* Configure the external interrupt source type */ - writel(0x00, sunxi_irq_base + SUNXI_IRQ_NMI_CTRL_REG); - - sunxi_irq_domain = irq_domain_add_linear(node, 3 * 32, - &sunxi_irq_ops, NULL); - if (!sunxi_irq_domain) - panic("%s: unable to create IRQ domain\n", node->full_name); - - return 0; -} - -static struct of_device_id sunxi_irq_dt_ids[] __initconst = { - { .compatible = "allwinner,sunxi-ic", .data = sunxi_of_init }, - { } -}; - -void __init sunxi_init_irq(void) -{ - of_irq_init(sunxi_irq_dt_ids); -} - -asmlinkage void __exception_irq_entry sunxi_handle_irq(struct pt_regs *regs) -{ - u32 irq, hwirq; - - hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2; - while (hwirq != 0) { - irq = irq_find_mapping(sunxi_irq_domain, hwirq); - handle_IRQ(irq, regs); - hwirq = readl(sunxi_irq_base + SUNXI_IRQ_VECTOR_REG) >> 2; - } -} diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c index 9dbd82b716d..065b7a31a47 100644 --- a/drivers/irqchip/irq-versatile-fpga.c +++ b/drivers/irqchip/irq-versatile-fpga.c @@ -139,7 +139,7 @@ void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, int i; if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { - pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); + pr_err("%s: too few FPGA IRQ controllers, increase CONFIG_VERSATILE_FPGA_IRQ_NR\n", __func__); return; } f = &fpga_irq_devices[fpga_irq_id]; diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 3cf97aaebe4..884d11c7355 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/list.h> #include <linux/io.h> +#include <linux/irq.h> #include <linux/irqdomain.h> #include <linux/of.h> #include <linux/of_address.h> @@ -33,7 +34,7 @@ #include <linux/irqchip/arm-vic.h> #include <asm/exception.h> -#include <asm/mach/irq.h> +#include <asm/irq.h> #include "irqchip.h" |