diff options
Diffstat (limited to 'drivers/irqchip')
59 files changed, 2017 insertions, 594 deletions
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 120d81543e53..27b52c8729cd 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -61,6 +61,10 @@ config ATMEL_AIC5_IRQ select MULTI_IRQ_HANDLER select SPARSE_IRQ +config I8259 + bool + select IRQ_DOMAIN + config BCM7038_L1_IRQ bool select GENERIC_IRQ_CHIP @@ -177,3 +181,9 @@ config RENESAS_H8300H_INTC config RENESAS_H8S_INTC bool select IRQ_DOMAIN + +config IMX_GPCV2 + bool + select IRQ_DOMAIN + help + Enables the wakeup IRQs for IMX platforms with GPCv2 block diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index b8d4e9691890..bb3048f00e64 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_IRQCHIP) += irqchip.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o +obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o @@ -22,11 +23,12 @@ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o -obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o +obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o obj-$(CONFIG_ARM_NVIC) += irq-nvic.o obj-$(CONFIG_ARM_VIC) += irq-vic.o obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o +obj-$(CONFIG_I8259) += irq-i8259.o obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o obj-$(CONFIG_IRQ_MIPS_CPU) += irq-mips-cpu.o obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o @@ -52,3 +54,4 @@ obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o +obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o diff --git a/drivers/irqchip/exynos-combiner.c b/drivers/irqchip/exynos-combiner.c index 5c82e3bdafdf..cd7d3bc78e34 100644 --- a/drivers/irqchip/exynos-combiner.c +++ b/drivers/irqchip/exynos-combiner.c @@ -15,13 +15,12 @@ #include <linux/slab.h> #include <linux/syscore_ops.h> #include <linux/irqdomain.h> +#include <linux/irqchip.h> #include <linux/irqchip/chained_irq.h> #include <linux/interrupt.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include "irqchip.h" - #define COMBINER_ENABLE_SET 0x0 #define COMBINER_ENABLE_CLEAR 0x4 #define COMBINER_INT_STATUS 0xC @@ -66,10 +65,10 @@ static void combiner_unmask_irq(struct irq_data *data) __raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET); } -static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) +static void combiner_handle_cascade_irq(struct irq_desc *desc) { - struct combiner_chip_data *chip_data = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct combiner_chip_data *chip_data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned int cascade_irq, combiner_irq; unsigned long status; @@ -87,7 +86,7 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc) cascade_irq = irq_find_mapping(combiner_irq_domain, combiner_irq); if (unlikely(!cascade_irq)) - handle_bad_irq(irq, desc); + handle_bad_irq(desc); else generic_handle_irq(cascade_irq); @@ -122,9 +121,8 @@ static struct irq_chip combiner_chip = { static void __init combiner_cascade_irq(struct combiner_chip_data *combiner_data, unsigned int irq) { - if (irq_set_handler_data(irq, combiner_data) != 0) - BUG(); - irq_set_chained_handler(irq, combiner_handle_cascade_irq); + irq_set_chained_handler_and_data(irq, combiner_handle_cascade_irq, + combiner_data); } static void __init combiner_init_one(struct combiner_chip_data *combiner_data, @@ -165,7 +163,7 @@ static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq); irq_set_chip_data(irq, &combiner_data[hw >> 3]); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); return 0; } @@ -185,14 +183,14 @@ static void __init combiner_init(void __iomem *combiner_base, combiner_data = kcalloc(max_nr, sizeof (*combiner_data), GFP_KERNEL); if (!combiner_data) { - pr_warning("%s: could not allocate combiner data\n", __func__); + pr_warn("%s: could not allocate combiner data\n", __func__); return; } combiner_irq_domain = irq_domain_add_linear(np, nr_irq, &combiner_irq_domain_ops, combiner_data); if (WARN_ON(!combiner_irq_domain)) { - pr_warning("%s: irq domain init failed\n", __func__); + pr_warn("%s: irq domain init failed\n", __func__); return; } diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c index 0d3b0fe2f175..655cb967a1f2 100644 --- a/drivers/irqchip/irq-armada-370-xp.c +++ b/drivers/irqchip/irq-armada-370-xp.c @@ -18,6 +18,7 @@ #include <linux/init.h> #include <linux/irq.h> #include <linux/interrupt.h> +#include <linux/irqchip.h> #include <linux/irqchip/chained_irq.h> #include <linux/cpu.h> #include <linux/io.h> @@ -33,8 +34,6 @@ #include <asm/smp_plat.h> #include <asm/mach/irq.h> -#include "irqchip.h" - /* Interrupt Controller Registers Map */ #define ARMADA_370_XP_INT_SET_MASK_OFFS (0x48) #define ARMADA_370_XP_INT_CLEAR_MASK_OFFS (0x4C) @@ -201,7 +200,6 @@ static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq, { irq_set_chip_and_handler(virq, &armada_370_xp_msi_irq_chip, handle_simple_irq); - set_irq_flags(virq, IRQF_VALID); return 0; } @@ -318,7 +316,7 @@ static int armada_370_xp_mpic_irq_map(struct irq_domain *h, irq_set_chip_and_handler(virq, &armada_370_xp_irq_chip, handle_level_irq); } - set_irq_flags(virq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(virq); return 0; } @@ -448,10 +446,9 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained) static void armada_370_xp_handle_msi_irq(struct pt_regs *r, bool b) {} #endif -static void armada_370_xp_mpic_handle_cascade_irq(unsigned int irq, - struct irq_desc *desc) +static void armada_370_xp_mpic_handle_cascade_irq(struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned long irqmap, irqn, irqsrc, cpuid; unsigned int cascade_irq; diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index dae3604b32a9..8a0c7f288198 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -19,6 +19,7 @@ #include <linux/bitmap.h> #include <linux/types.h> #include <linux/irq.h> +#include <linux/irqchip.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> @@ -31,7 +32,6 @@ #include <asm/mach/irq.h> #include "irq-atmel-aic-common.h" -#include "irqchip.h" /* Number of irq lines managed by AIC */ #define NR_AIC_IRQS 32 @@ -225,7 +225,7 @@ static void __init at91sam9g45_aic_irq_fixup(struct device_node *root) aic_common_rtt_irq_fixup(root); } -static const struct of_device_id __initdata aic_irq_fixups[] = { +static const struct of_device_id aic_irq_fixups[] __initconst = { { .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup }, { .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup }, { .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup }, diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 459bf4429d36..f6d680485bee 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -19,6 +19,7 @@ #include <linux/bitmap.h> #include <linux/types.h> #include <linux/irq.h> +#include <linux/irqchip.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> @@ -31,7 +32,6 @@ #include <asm/mach/irq.h> #include "irq-atmel-aic-common.h" -#include "irqchip.h" /* Number of irq lines managed by AIC */ #define NR_AIC5_IRQS 128 @@ -88,28 +88,36 @@ static void aic5_mask(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - /* Disable interrupt on AIC5 */ - irq_gc_lock(gc); + /* + * Disable interrupt on AIC5. We always take the lock of the + * first irq chip as all chips share the same registers. + */ + irq_gc_lock(bgc); irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); irq_reg_writel(gc, 1, AT91_AIC5_IDCR); gc->mask_cache &= ~d->mask; - irq_gc_unlock(gc); + irq_gc_unlock(bgc); } static void aic5_unmask(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - /* Enable interrupt on AIC5 */ - irq_gc_lock(gc); + /* + * Enable interrupt on AIC5. We always take the lock of the + * first irq chip as all chips share the same registers. + */ + irq_gc_lock(bgc); irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); irq_reg_writel(gc, 1, AT91_AIC5_IECR); gc->mask_cache |= d->mask; - irq_gc_unlock(gc); + irq_gc_unlock(bgc); } static int aic5_retrigger(struct irq_data *d) @@ -290,7 +298,7 @@ static void __init sama5d3_aic_irq_fixup(struct device_node *root) aic_common_rtc_irq_fixup(root); } -static const struct of_device_id __initdata aic5_irq_fixups[] = { +static const struct of_device_id aic5_irq_fixups[] __initconst = { { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, { .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup }, { /* sentinel */ }, diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index e68c3b60a681..bf9cc5f2e839 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -48,13 +48,12 @@ #include <linux/slab.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/irqchip.h> #include <linux/irqdomain.h> #include <asm/exception.h> #include <asm/mach/irq.h> -#include "irqchip.h" - /* Put the bank and irq (32 bits) into the hwirq */ #define MAKE_HWIRQ(b, n) ((b << 5) | (n)) #define HWIRQ_BANK(i) (i >> 5) @@ -76,10 +75,10 @@ #define NR_BANKS 3 #define IRQS_PER_BANK 32 -static int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; -static int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; -static int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; -static int bank_irqs[] __initconst = { 8, 32, 32 }; +static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; +static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; +static const int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; +static const int bank_irqs[] __initconst = { 8, 32, 32 }; static const int shortcuts[] = { 7, 9, 10, 18, 19, /* Bank 1 */ @@ -97,6 +96,7 @@ struct armctrl_ic { static struct armctrl_ic intc __read_mostly; static void __exception_irq_entry bcm2835_handle_irq( struct pt_regs *regs); +static void bcm2836_chained_handle_irq(struct irq_desc *desc); static void armctrl_mask_irq(struct irq_data *d) { @@ -140,7 +140,8 @@ static const struct irq_domain_ops armctrl_ops = { }; static int __init armctrl_of_init(struct device_node *node, - struct device_node *parent) + struct device_node *parent, + bool is_2836) { void __iomem *base; int irq, b, i; @@ -165,58 +166,94 @@ static int __init armctrl_of_init(struct device_node *node, BUG_ON(irq <= 0); irq_set_chip_and_handler(irq, &armctrl_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_probe(irq); + } + } + + if (is_2836) { + int parent_irq = irq_of_parse_and_map(node, 0); + + if (!parent_irq) { + panic("%s: unable to get parent interrupt.\n", + node->full_name); } + irq_set_chained_handler(parent_irq, bcm2836_chained_handle_irq); + } else { + set_handle_irq(bcm2835_handle_irq); } - set_handle_irq(bcm2835_handle_irq); return 0; } +static int __init bcm2835_armctrl_of_init(struct device_node *node, + struct device_node *parent) +{ + return armctrl_of_init(node, parent, false); +} + +static int __init bcm2836_armctrl_of_init(struct device_node *node, + struct device_node *parent) +{ + return armctrl_of_init(node, parent, true); +} + + /* * Handle each interrupt across the entire interrupt controller. This reads the * status register before handling each interrupt, which is necessary given that * handle_IRQ may briefly re-enable interrupts for soft IRQ handling. */ -static void armctrl_handle_bank(int bank, struct pt_regs *regs) +static u32 armctrl_translate_bank(int bank) { - u32 stat, irq; + u32 stat = readl_relaxed(intc.pending[bank]); - while ((stat = readl_relaxed(intc.pending[bank]))) { - irq = MAKE_HWIRQ(bank, ffs(stat) - 1); - handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); - } + return MAKE_HWIRQ(bank, ffs(stat) - 1); +} + +static u32 armctrl_translate_shortcut(int bank, u32 stat) +{ + return MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]); } -static void armctrl_handle_shortcut(int bank, struct pt_regs *regs, - u32 stat) +static u32 get_next_armctrl_hwirq(void) { - u32 irq = MAKE_HWIRQ(bank, shortcuts[ffs(stat >> SHORTCUT_SHIFT) - 1]); - handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); + u32 stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK; + + if (stat == 0) + return ~0; + else if (stat & BANK0_HWIRQ_MASK) + return MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1); + else if (stat & SHORTCUT1_MASK) + return armctrl_translate_shortcut(1, stat & SHORTCUT1_MASK); + else if (stat & SHORTCUT2_MASK) + return armctrl_translate_shortcut(2, stat & SHORTCUT2_MASK); + else if (stat & BANK1_HWIRQ) + return armctrl_translate_bank(1); + else if (stat & BANK2_HWIRQ) + return armctrl_translate_bank(2); + else + BUG(); } static void __exception_irq_entry bcm2835_handle_irq( struct pt_regs *regs) { - u32 stat, irq; - - while ((stat = readl_relaxed(intc.pending[0]) & BANK0_VALID_MASK)) { - if (stat & BANK0_HWIRQ_MASK) { - irq = MAKE_HWIRQ(0, ffs(stat & BANK0_HWIRQ_MASK) - 1); - handle_IRQ(irq_linear_revmap(intc.domain, irq), regs); - } else if (stat & SHORTCUT1_MASK) { - armctrl_handle_shortcut(1, regs, stat & SHORTCUT1_MASK); - } else if (stat & SHORTCUT2_MASK) { - armctrl_handle_shortcut(2, regs, stat & SHORTCUT2_MASK); - } else if (stat & BANK1_HWIRQ) { - armctrl_handle_bank(1, regs); - } else if (stat & BANK2_HWIRQ) { - armctrl_handle_bank(2, regs); - } else { - BUG(); - } - } + u32 hwirq; + + while ((hwirq = get_next_armctrl_hwirq()) != ~0) + handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs); +} + +static void bcm2836_chained_handle_irq(struct irq_desc *desc) +{ + u32 hwirq; + + while ((hwirq = get_next_armctrl_hwirq()) != ~0) + generic_handle_irq(irq_linear_revmap(intc.domain, hwirq)); } -IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", armctrl_of_init); +IRQCHIP_DECLARE(bcm2835_armctrl_ic, "brcm,bcm2835-armctrl-ic", + bcm2835_armctrl_of_init); +IRQCHIP_DECLARE(bcm2836_armctrl_ic, "brcm,bcm2836-armctrl-ic", + bcm2836_armctrl_of_init); diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c new file mode 100644 index 000000000000..f68708281fcf --- /dev/null +++ b/drivers/irqchip/irq-bcm2836.c @@ -0,0 +1,275 @@ +/* + * Root interrupt controller for the BCM2836 (Raspberry Pi 2). + * + * Copyright 2015 Broadcom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/cpu.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/irqchip.h> +#include <linux/irqdomain.h> +#include <asm/exception.h> + +/* + * The low 2 bits identify the CPU that the GPU IRQ goes to, and the + * next 2 bits identify the CPU that the GPU FIQ goes to. + */ +#define LOCAL_GPU_ROUTING 0x00c +/* When setting bits 0-3, enables PMU interrupts on that CPU. */ +#define LOCAL_PM_ROUTING_SET 0x010 +/* When setting bits 0-3, disables PMU interrupts on that CPU. */ +#define LOCAL_PM_ROUTING_CLR 0x014 +/* + * The low 4 bits of this are the CPU's timer IRQ enables, and the + * next 4 bits are the CPU's timer FIQ enables (which override the IRQ + * bits). + */ +#define LOCAL_TIMER_INT_CONTROL0 0x040 +/* + * The low 4 bits of this are the CPU's per-mailbox IRQ enables, and + * the next 4 bits are the CPU's per-mailbox FIQ enables (which + * override the IRQ bits). + */ +#define LOCAL_MAILBOX_INT_CONTROL0 0x050 +/* + * The CPU's interrupt status register. Bits are defined by the the + * LOCAL_IRQ_* bits below. + */ +#define LOCAL_IRQ_PENDING0 0x060 +/* Same status bits as above, but for FIQ. */ +#define LOCAL_FIQ_PENDING0 0x070 +/* + * Mailbox0 write-to-set bits. There are 16 mailboxes, 4 per CPU, and + * these bits are organized by mailbox number and then CPU number. We + * use mailbox 0 for IPIs. The mailbox's interrupt is raised while + * any bit is set. + */ +#define LOCAL_MAILBOX0_SET0 0x080 +/* Mailbox0 write-to-clear bits. */ +#define LOCAL_MAILBOX0_CLR0 0x0c0 + +#define LOCAL_IRQ_CNTPSIRQ 0 +#define LOCAL_IRQ_CNTPNSIRQ 1 +#define LOCAL_IRQ_CNTHPIRQ 2 +#define LOCAL_IRQ_CNTVIRQ 3 +#define LOCAL_IRQ_MAILBOX0 4 +#define LOCAL_IRQ_MAILBOX1 5 +#define LOCAL_IRQ_MAILBOX2 6 +#define LOCAL_IRQ_MAILBOX3 7 +#define LOCAL_IRQ_GPU_FAST 8 +#define LOCAL_IRQ_PMU_FAST 9 +#define LAST_IRQ LOCAL_IRQ_PMU_FAST + +struct bcm2836_arm_irqchip_intc { + struct irq_domain *domain; + void __iomem *base; +}; + +static struct bcm2836_arm_irqchip_intc intc __read_mostly; + +static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset, + unsigned int bit, + int cpu) +{ + void __iomem *reg = intc.base + reg_offset + 4 * cpu; + + writel(readl(reg) & ~BIT(bit), reg); +} + +static void bcm2836_arm_irqchip_unmask_per_cpu_irq(unsigned int reg_offset, + unsigned int bit, + int cpu) +{ + void __iomem *reg = intc.base + reg_offset + 4 * cpu; + + writel(readl(reg) | BIT(bit), reg); +} + +static void bcm2836_arm_irqchip_mask_timer_irq(struct irq_data *d) +{ + bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, + d->hwirq - LOCAL_IRQ_CNTPSIRQ, + smp_processor_id()); +} + +static void bcm2836_arm_irqchip_unmask_timer_irq(struct irq_data *d) +{ + bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_TIMER_INT_CONTROL0, + d->hwirq - LOCAL_IRQ_CNTPSIRQ, + smp_processor_id()); +} + +static struct irq_chip bcm2836_arm_irqchip_timer = { + .name = "bcm2836-timer", + .irq_mask = bcm2836_arm_irqchip_mask_timer_irq, + .irq_unmask = bcm2836_arm_irqchip_unmask_timer_irq, +}; + +static void bcm2836_arm_irqchip_mask_pmu_irq(struct irq_data *d) +{ + writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_CLR); +} + +static void bcm2836_arm_irqchip_unmask_pmu_irq(struct irq_data *d) +{ + writel(1 << smp_processor_id(), intc.base + LOCAL_PM_ROUTING_SET); +} + +static struct irq_chip bcm2836_arm_irqchip_pmu = { + .name = "bcm2836-pmu", + .irq_mask = bcm2836_arm_irqchip_mask_pmu_irq, + .irq_unmask = bcm2836_arm_irqchip_unmask_pmu_irq, +}; + +static void bcm2836_arm_irqchip_mask_gpu_irq(struct irq_data *d) +{ +} + +static void bcm2836_arm_irqchip_unmask_gpu_irq(struct irq_data *d) +{ +} + +static struct irq_chip bcm2836_arm_irqchip_gpu = { + .name = "bcm2836-gpu", + .irq_mask = bcm2836_arm_irqchip_mask_gpu_irq, + .irq_unmask = bcm2836_arm_irqchip_unmask_gpu_irq, +}; + +static void bcm2836_arm_irqchip_register_irq(int hwirq, struct irq_chip *chip) +{ + int irq = irq_create_mapping(intc.domain, hwirq); + + irq_set_percpu_devid(irq); + irq_set_chip_and_handler(irq, chip, handle_percpu_devid_irq); + irq_set_status_flags(irq, IRQ_NOAUTOEN); +} + +static void +__exception_irq_entry bcm |