From 6ef930f20c30f8a7dcffa50fa9f33a9211727a6e Mon Sep 17 00:00:00 2001 From: Marc Zyngier <marc.zyngier@arm.com> Date: Tue, 7 Nov 2017 10:04:38 +0000 Subject: irqchip/gic-v3-its: Fix VPE activate callback return value its_vpe_irq_domain_activate should always return 0. Really. There is not a single case why it wouldn't. So this "return true;" is really a copy/paste issue that got revealed now that we actually check the return value of the activate method. Brown paper bag day. Fixes: 2247e1bf7063 ("irqchip/gic-v3-its: Limit scope of VPE mapping to be per ITS") Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/irq-gic-v3-its.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 29b2ff5c6841..be99d59bf636 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -2802,7 +2802,7 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain, /* If we use the list map, we issue VMAPP on demand... */ if (its_list_map) - return true; + return 0; /* Map the VPE to the first possible CPU */ vpe->col_idx = cpumask_first(cpu_online_mask); -- cgit From 706cffc1b912342668e621526c860fb093dfc2d5 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel <ard.biesheuvel@linaro.org> Date: Mon, 6 Nov 2017 18:34:37 +0000 Subject: irqchip/exiu: Add support for Socionext Synquacer EXIU controller The Socionext Synquacer SoC has an external interrupt unit (EXIU) that forwards a block of 32 configurable input lines to 32 adjacent level-high type GICv3 SPIs. The EXIU has per-interrupt level/edge and polarity controls, and mask bits that keep the outgoing lines de-asserted, even though the controller may still latch interrupt conditions that occur while the line is masked. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-sni-exiu.c | 227 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 drivers/irqchip/irq-sni-exiu.c (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 065adf4102c9..dee3390390d5 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -79,4 +79,5 @@ obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o +obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o diff --git a/drivers/irqchip/irq-sni-exiu.c b/drivers/irqchip/irq-sni-exiu.c new file mode 100644 index 000000000000..1b6e2f7c59af --- /dev/null +++ b/drivers/irqchip/irq-sni-exiu.c @@ -0,0 +1,227 @@ +/* + * Driver for Socionext External Interrupt Unit (EXIU) + * + * Copyright (c) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org> + * + * Based on irq-tegra.c: + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2010,2013, NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/irqchip.h> +#include <linux/irqdomain.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> + +#include <dt-bindings/interrupt-controller/arm-gic.h> + +#define NUM_IRQS 32 + +#define EIMASK 0x00 +#define EISRCSEL 0x04 +#define EIREQSTA 0x08 +#define EIRAWREQSTA 0x0C +#define EIREQCLR 0x10 +#define EILVL 0x14 +#define EIEDG 0x18 +#define EISIR 0x1C + +struct exiu_irq_data { + void __iomem *base; + u32 spi_base; +}; + +static void exiu_irq_eoi(struct irq_data *d) +{ + struct exiu_irq_data *data = irq_data_get_irq_chip_data(d); + + writel(BIT(d->hwirq), data->base + EIREQCLR); + irq_chip_eoi_parent(d); +} + +static void exiu_irq_mask(struct irq_data *d) +{ + struct exiu_irq_data *data = irq_data_get_irq_chip_data(d); + u32 val; + + val = readl_relaxed(data->base + EIMASK) | BIT(d->hwirq); + writel_relaxed(val, data->base + EIMASK); + irq_chip_mask_parent(d); +} + +static void exiu_irq_unmask(struct irq_data *d) +{ + struct exiu_irq_data *data = irq_data_get_irq_chip_data(d); + u32 val; + + val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq); + writel_relaxed(val, data->base + EIMASK); + irq_chip_unmask_parent(d); +} + +static void exiu_irq_enable(struct irq_data *d) +{ + struct exiu_irq_data *data = irq_data_get_irq_chip_data(d); + u32 val; + + /* clear interrupts that were latched while disabled */ + writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR); + + val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq); + writel_relaxed(val, data->base + EIMASK); + irq_chip_enable_parent(d); +} + +static int exiu_irq_set_type(struct irq_data *d, unsigned int type) +{ + struct exiu_irq_data *data = irq_data_get_irq_chip_data(d); + u32 val; + + val = readl_relaxed(data->base + EILVL); + if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH) + val |= BIT(d->hwirq); + else + val &= ~BIT(d->hwirq); + writel_relaxed(val, data->base + EILVL); + + val = readl_relaxed(data->base + EIEDG); + if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) + val &= ~BIT(d->hwirq); + else + val |= BIT(d->hwirq); + writel_relaxed(val, data->base + EIEDG); + + writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR); + + return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH); +} + +static struct irq_chip exiu_irq_chip = { + .name = "EXIU", + .irq_eoi = exiu_irq_eoi, + .irq_enable = exiu_irq_enable, + .irq_mask = exiu_irq_mask, + .irq_unmask = exiu_irq_unmask, + .irq_set_type = exiu_irq_set_type, + .irq_set_affinity = irq_chip_set_affinity_parent, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_EOI_THREADED | + IRQCHIP_MASK_ON_SUSPEND, +}; + +static int exiu_domain_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + struct exiu_irq_data *info = domain->host_data; + + if (is_of_node(fwspec->fwnode)) { + if (fwspec->param_count != 3) + return -EINVAL; + + if (fwspec->param[0] != GIC_SPI) + return -EINVAL; /* No PPI should point to this domain */ + + *hwirq = fwspec->param[1] - info->spi_base; + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + return 0; + } + return -EINVAL; +} + +static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq, + unsigned int nr_irqs, void *data) +{ + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; + struct exiu_irq_data *info = dom->host_data; + irq_hw_number_t hwirq; + + if (fwspec->param_count != 3) + return -EINVAL; /* Not GIC compliant */ + if (fwspec->param[0] != GIC_SPI) + return -EINVAL; /* No PPI should point to this domain */ + + WARN_ON(nr_irqs != 1); + hwirq = fwspec->param[1] - info->spi_base; + irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info); + + parent_fwspec = *fwspec; + parent_fwspec.fwnode = dom->parent->fwnode; + return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec); +} + +static const struct irq_domain_ops exiu_domain_ops = { + .translate = exiu_domain_translate, + .alloc = exiu_domain_alloc, + .free = irq_domain_free_irqs_common, +}; + +static int __init exiu_init(struct device_node *node, + struct device_node *parent) +{ + struct irq_domain *parent_domain, *domain; + struct exiu_irq_data *data; + int err; + + if (!parent) { + pr_err("%pOF: no parent, giving up\n", node); + return -ENODEV; + } + + parent_domain = irq_find_host(parent); + if (!parent_domain) { + pr_err("%pOF: unable to obtain parent domain\n", node); + return -ENXIO; + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (of_property_read_u32(node, "socionext,spi-base", &data->spi_base)) { + pr_err("%pOF: failed to parse 'spi-base' property\n", node); + err = -ENODEV; + goto out_free; + } + + data->base = of_iomap(node, 0); + if (IS_ERR(data->base)) { + err = PTR_ERR(data->base); + goto out_free; + } + + /* clear and mask all interrupts */ + writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR); + writel_relaxed(0xFFFFFFFF, data->base + EIMASK); + + domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node, + &exiu_domain_ops, data); + if (!domain) { + pr_err("%pOF: failed to allocate domain\n", node); + err = -ENOMEM; + goto out_unmap; + } + + pr_info("%pOF: %d interrupts forwarded to %pOF\n", node, NUM_IRQS, + parent); + + return 0; + +out_unmap: + iounmap(data->base); +out_free: + kfree(data); + return err; +} +IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init); -- cgit From 0e7d780721bd259d061ac0c1076e40e326d1b32b Mon Sep 17 00:00:00 2001 From: Ludovic Barre <ludovic.barre@st.com> Date: Mon, 6 Nov 2017 18:03:31 +0100 Subject: irqchip/stm32: Select GENERIC_IRQ_CHIP This patch adds GENERIC_IRQ_CHIP to stm32 exti config. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 1cb39405d7f8..ccfb14de57e4 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -306,6 +306,7 @@ config EZNPS_GIC config STM32_EXTI bool select IRQ_DOMAIN + select GENERIC_IRQ_CHIP config QCOM_IRQ_COMBINER bool "QCOM IRQ combiner support" -- cgit From 6dd64ee17e04c3949f21630b6426f149252ff8b1 Mon Sep 17 00:00:00 2001 From: Ludovic Barre <ludovic.barre@st.com> Date: Mon, 6 Nov 2017 18:03:32 +0100 Subject: irqchip/stm32: Add multi-bank management -Prepare to manage multi-bank of external interrupts (N banks of 32 inputs). -Prepare to manage registers offsets by compatible (registers offsets could be different follow per stm32 platform). Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/irq-stm32-exti.c | 149 +++++++++++++++++++++++++++------------ 1 file changed, 103 insertions(+), 46 deletions(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 45363ff8d06f..ef378709baea 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -14,27 +14,66 @@ #include <linux/of_address.h> #include <linux/of_irq.h> -#define EXTI_IMR 0x0 -#define EXTI_EMR 0x4 -#define EXTI_RTSR 0x8 -#define EXTI_FTSR 0xc -#define EXTI_SWIER 0x10 -#define EXTI_PR 0x14 +#define IRQS_PER_BANK 32 + +struct stm32_exti_bank { + u32 imr_ofst; + u32 emr_ofst; + u32 rtsr_ofst; + u32 ftsr_ofst; + u32 swier_ofst; + u32 pr_ofst; +}; + +static const struct stm32_exti_bank stm32f4xx_exti_b1 = { + .imr_ofst = 0x00, + .emr_ofst = 0x04, + .rtsr_ofst = 0x08, + .ftsr_ofst = 0x0C, + .swier_ofst = 0x10, + .pr_ofst = 0x14, +}; + +static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { + &stm32f4xx_exti_b1, +}; + +static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + return irq_reg_readl(gc, stm32_bank->pr_ofst); +} + +static void stm32_exti_irq_ack(struct irq_chip_generic *gc, u32 mask) +{ + const struct stm32_exti_bank *stm32_bank = gc->private; + + irq_reg_writel(gc, mask, stm32_bank->pr_ofst); +} static void stm32_irq_handler(struct irq_desc *desc) { struct irq_domain *domain = irq_desc_get_handler_data(desc); - struct irq_chip_generic *gc = domain->gc->gc[0]; struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int virq, nbanks = domain->gc->num_chips; + struct irq_chip_generic *gc; + const struct stm32_exti_bank *stm32_bank; unsigned long pending; - int n; + int n, i, irq_base = 0; chained_irq_enter(chip, desc); - while ((pending = irq_reg_readl(gc, EXTI_PR))) { - for_each_set_bit(n, &pending, BITS_PER_LONG) { - generic_handle_irq(irq_find_mapping(domain, n)); - irq_reg_writel(gc, BIT(n), EXTI_PR); + for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) { + gc = irq_get_domain_generic_chip(domain, irq_base); + stm32_bank = gc->private; + + while ((pending = stm32_exti_pending(gc))) { + for_each_set_bit(n, &pending, IRQS_PER_BANK) { + virq = irq_find_mapping(domain, irq_base + n); + generic_handle_irq(virq); + stm32_exti_irq_ack(gc, BIT(n)); + } } } @@ -44,13 +83,14 @@ static void stm32_irq_handler(struct irq_desc *desc) static int stm32_irq_set_type(struct irq_data *data, unsigned int type) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 rtsr, ftsr; irq_gc_lock(gc); - rtsr = irq_reg_readl(gc, EXTI_RTSR); - ftsr = irq_reg_readl(gc, EXTI_FTSR); + rtsr = irq_reg_readl(gc, stm32_bank->rtsr_ofst); + ftsr = irq_reg_readl(gc, stm32_bank->ftsr_ofst); switch (type) { case IRQ_TYPE_EDGE_RISING: @@ -70,8 +110,8 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) return -EINVAL; } - irq_reg_writel(gc, rtsr, EXTI_RTSR); - irq_reg_writel(gc, ftsr, EXTI_FTSR); + irq_reg_writel(gc, rtsr, stm32_bank->rtsr_ofst); + irq_reg_writel(gc, ftsr, stm32_bank->ftsr_ofst); irq_gc_unlock(gc); @@ -81,17 +121,18 @@ static int stm32_irq_set_type(struct irq_data *data, unsigned int type) static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) { struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); - int pin = data->hwirq; + const struct stm32_exti_bank *stm32_bank = gc->private; + int pin = data->hwirq % IRQS_PER_BANK; u32 emr; irq_gc_lock(gc); - emr = irq_reg_readl(gc, EXTI_EMR); + emr = irq_reg_readl(gc, stm32_bank->emr_ofst); if (on) emr |= BIT(pin); else emr &= ~BIT(pin); - irq_reg_writel(gc, emr, EXTI_EMR); + irq_reg_writel(gc, emr, stm32_bank->emr_ofst); irq_gc_unlock(gc); @@ -101,11 +142,12 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) static int stm32_exti_alloc(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *data) { - struct irq_chip_generic *gc = d->gc->gc[0]; + struct irq_chip_generic *gc; struct irq_fwspec *fwspec = data; irq_hw_number_t hwirq; hwirq = fwspec->param[0]; + gc = irq_get_domain_generic_chip(d, hwirq); irq_map_generic_chip(d, virq, hwirq); irq_domain_set_info(d, virq, hwirq, &gc->chip_types->chip, gc, @@ -129,8 +171,9 @@ struct irq_domain_ops irq_exti_domain_ops = { .free = stm32_exti_free, }; -static int __init stm32_exti_init(struct device_node *node, - struct device_node *parent) +static int +__init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, + int bank_nr, struct device_node *node) { unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN; int nr_irqs, nr_exti, ret, i; @@ -144,23 +187,16 @@ static int __init stm32_exti_init(struct device_node *node, return -ENOMEM; } - /* Determine number of irqs supported */ - writel_relaxed(~0UL, base + EXTI_RTSR); - nr_exti = fls(readl_relaxed(base + EXTI_RTSR)); - writel_relaxed(0, base + EXTI_RTSR); - - pr_info("%pOF: %d External IRQs detected\n", node, nr_exti); - - domain = irq_domain_add_linear(node, nr_exti, + domain = irq_domain_add_linear(node, bank_nr * IRQS_PER_BANK, &irq_exti_domain_ops, NULL); if (!domain) { pr_err("%s: Could not register interrupt domain.\n", - node->name); + node->name); ret = -ENOMEM; goto out_unmap; } - ret = irq_alloc_domain_generic_chips(domain, nr_exti, 1, "exti", + ret = irq_alloc_domain_generic_chips(domain, IRQS_PER_BANK, 1, "exti", handle_edge_irq, clr, 0, 0); if (ret) { pr_err("%pOF: Could not allocate generic interrupt chip.\n", @@ -168,18 +204,32 @@ static int __init stm32_exti_init(struct device_node *node, goto out_free_domain; } - gc = domain->gc->gc[0]; - gc->reg_base = base; - gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; - gc->chip_types->chip.name = gc->chip_types[0].chip.name; - gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; - gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; - gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; - gc->chip_types->chip.irq_set_type = stm32_irq_set_type; - gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; - gc->chip_types->regs.ack = EXTI_PR; - gc->chip_types->regs.mask = EXTI_IMR; - gc->chip_types->handler = handle_edge_irq; + for (i = 0; i < bank_nr; i++) { + const struct stm32_exti_bank *stm32_bank = stm32_exti_banks[i]; + u32 irqs_mask; + + gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK); + + gc->reg_base = base; + gc->chip_types->type = IRQ_TYPE_EDGE_BOTH; + gc->chip_types->chip.irq_ack = irq_gc_ack_set_bit; + gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit; + gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit; + gc->chip_types->chip.irq_set_type = stm32_irq_set_type; + gc->chip_types->chip.irq_set_wake = stm32_irq_set_wake; + gc->chip_types->regs.ack = stm32_bank->pr_ofst; + gc->chip_types->regs.mask = stm32_bank->imr_ofst; + gc->private = (void *)stm32_bank; + + /* Determine number of irqs supported */ + writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); + irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); + nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); + writel_relaxed(0, base + stm32_bank->rtsr_ofst); + + pr_info("%s: bank%d, External IRQs available:%#x\n", + node->full_name, i, irqs_mask); + } nr_irqs = of_irq_count(node); for (i = 0; i < nr_irqs; i++) { @@ -198,4 +248,11 @@ out_unmap: return ret; } -IRQCHIP_DECLARE(stm32_exti, "st,stm32-exti", stm32_exti_init); +static int __init stm32f4_exti_of_init(struct device_node *np, + struct device_node *parent) +{ + return stm32_exti_init(stm32f4xx_exti_banks, + ARRAY_SIZE(stm32f4xx_exti_banks), np); +} + +IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); -- cgit From 539c603e147c1566f90623d863fa0d64ecb6c89d Mon Sep 17 00:00:00 2001 From: Ludovic Barre <ludovic.barre@st.com> Date: Mon, 6 Nov 2017 18:03:34 +0100 Subject: irqchip/stm32: Add stm32h7 support stm32h7 has up to 96 inputs (3 banks of 32 inputs max). Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/irq-stm32-exti.c | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index ef378709baea..8f409a95918f 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -38,6 +38,39 @@ static const struct stm32_exti_bank *stm32f4xx_exti_banks[] = { &stm32f4xx_exti_b1, }; +static const struct stm32_exti_bank stm32h7xx_exti_b1 = { + .imr_ofst = 0x80, + .emr_ofst = 0x84, + .rtsr_ofst = 0x00, + .ftsr_ofst = 0x04, + .swier_ofst = 0x08, + .pr_ofst = 0x88, +}; + +static const struct stm32_exti_bank stm32h7xx_exti_b2 = { + .imr_ofst = 0x90, + .emr_ofst = 0x94, + .rtsr_ofst = 0x20, + .ftsr_ofst = 0x24, + .swier_ofst = 0x28, + .pr_ofst = 0x98, +}; + +static const struct stm32_exti_bank stm32h7xx_exti_b3 = { + .imr_ofst = 0xA0, + .emr_ofst = 0xA4, + .rtsr_ofst = 0x40, + .ftsr_ofst = 0x44, + .swier_ofst = 0x48, + .pr_ofst = 0xA8, +}; + +static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = { + &stm32h7xx_exti_b1, + &stm32h7xx_exti_b2, + &stm32h7xx_exti_b3, +}; + static unsigned long stm32_exti_pending(struct irq_chip_generic *gc) { const struct stm32_exti_bank *stm32_bank = gc->private; @@ -256,3 +289,12 @@ static int __init stm32f4_exti_of_init(struct device_node *np, } IRQCHIP_DECLARE(stm32f4_exti, "st,stm32-exti", stm32f4_exti_of_init); + +static int __init stm32h7_exti_of_init(struct device_node *np, + struct device_node *parent) +{ + return stm32_exti_init(stm32h7xx_exti_banks, + ARRAY_SIZE(stm32h7xx_exti_banks), np); +} + +IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init); -- cgit From 2ca6b9bcaad4a78af255be9e16b3f3062a6d7c32 Mon Sep 17 00:00:00 2001 From: Ludovic Barre <ludovic.barre@st.com> Date: Mon, 6 Nov 2017 18:03:35 +0100 Subject: irqchip/stm32: Fix initial values -After cold boot, imr default value depends on hardware configuration. -After hot reboot the registers must be cleared to avoid residue. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/irq-stm32-exti.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 8f409a95918f..477d0faf0ea2 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -258,7 +258,16 @@ __init stm32_exti_init(const struct stm32_exti_bank **stm32_exti_banks, writel_relaxed(~0UL, base + stm32_bank->rtsr_ofst); irqs_mask = readl_relaxed(base + stm32_bank->rtsr_ofst); nr_exti = fls(readl_relaxed(base + stm32_bank->rtsr_ofst)); + + /* + * This IP has no reset, so after hot reboot we should + * clear registers to avoid residue + */ + writel_relaxed(0, base + stm32_bank->imr_ofst); + writel_relaxed(0, base + stm32_bank->emr_ofst); writel_relaxed(0, base + stm32_bank->rtsr_ofst); + writel_relaxed(0, base + stm32_bank->ftsr_ofst); + writel_relaxed(~0UL, base + stm32_bank->pr_ofst); pr_info("%s: bank%d, External IRQs available:%#x\n", node->full_name, i, irqs_mask); -- cgit From 90af7c254ffb94b0df47bf6f613e3f3173df05d1 Mon Sep 17 00:00:00 2001 From: Ludovic Barre <ludovic.barre@st.com> Date: Mon, 6 Nov 2017 18:03:36 +0100 Subject: irqchip/stm32: Move the wakeup on interrupt mask Move irq_set_wake on interrupt mask, needed to wake up from low power mode as the event mask is not able to do so. Signed-off-by: Ludovic Barre <ludovic.barre@st.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/irq-stm32-exti.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c index 477d0faf0ea2..31ab0dee2ce7 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c @@ -156,16 +156,16 @@ static int stm32_irq_set_wake(struct irq_data *data, unsigned int on) struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); const struct stm32_exti_bank *stm32_bank = gc->private; int pin = data->hwirq % IRQS_PER_BANK; - u32 emr; + u32 imr; irq_gc_lock(gc); - emr = irq_reg_readl(gc, stm32_bank->emr_ofst); + imr = irq_reg_readl(gc, stm32_bank->imr_ofst); if (on) - emr |= BIT(pin); + imr |= BIT(pin); else - emr &= ~BIT(pin); - irq_reg_writel(gc, emr, stm32_bank->emr_ofst); + imr &= ~BIT(pin); + irq_reg_writel(gc, imr, stm32_bank->imr_ofst); irq_gc_unlock(gc); -- cgit From 1f19aee0ec404112cec08f0c852fcd291690fbc7 Mon Sep 17 00:00:00 2001 From: Matt Redfearn <matt.redfearn@mips.com> Date: Thu, 9 Nov 2017 11:02:44 +0000 Subject: irqchip/mips-gic: Add pr_fmt and reword pr_* messages Several messages from the MIPS GIC driver include the text "GIC", but the format is not standard. Add a pr_fmt of "irq-mips-gic: " and reword the messages now that they will be prefixed with the driver name. Signed-off-by: Matt Redfearn <matt.redfearn@mips.com> Reviewed-by: Paul Burton <paul.burton@mips.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/irq-mips-gic.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 3ccebb020f40..9b768899f07b 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -6,6 +6,9 @@ * Copyright (C) 2008 Ralf Baechle (ralf@linux-mips.org) * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. */ + +#define pr_fmt(fmt) "irq-mips-gic: " fmt + #include <linux/bitmap.h> #include <linux/clocksource.h> #include <linux/cpuhotplug.h> @@ -685,7 +688,7 @@ static int __init gic_of_init(struct device_node *node, cpu_vec = find_first_zero_bit(&reserved, hweight_long(ST0_IM)); if (cpu_vec == hweight_long(ST0_IM)) { - pr_err("No CPU vectors available for GIC\n"); + pr_err("No CPU vectors available\n"); return -ENODEV; } @@ -699,7 +702,7 @@ static int __init gic_of_init(struct device_node *node, ~CM_GCR_GIC_BASE_GICEN; gic_len = 0x20000; } else { - pr_err("Failed to get GIC memory range\n"); + pr_err("Failed to get memory range\n"); return -ENODEV; } } else { @@ -757,7 +760,7 @@ static int __init gic_of_init(struct device_node *node, gic_shared_intrs, 0, &gic_irq_domain_ops, NULL); if (!gic_irq_domain) { - pr_err("Failed to add GIC IRQ domain"); + pr_err("Failed to add IRQ domain"); return -ENXIO; } @@ -766,7 +769,7 @@ static int __init gic_of_init(struct device_node *node, GIC_NUM_LOCAL_INTRS + gic_shared_intrs, node, &gic_ipi_domain_ops, NULL); if (!gic_ipi_domain) { - pr_err("Failed to add GIC IPI domain"); + pr_err("Failed to add IPI domain"); return -ENXIO; } -- cgit From 666740fde412567aa0a8ea251ffee3004a6fa3a6 Mon Sep 17 00:00:00 2001 From: Matt Redfearn <matt.redfearn@mips.com> Date: Thu, 9 Nov 2017 11:02:45 +0000 Subject: irqchip: mips-gic: Print warning if inherited GIC base is used If the physical address of the GIC resource cannot be read from device tree, then the code falls back to reading it from the gcr_gic_base register. Hopefully this has been set to a sane value by the bootloader or some platform code, but is defined by the hardware manual to have "undefined" reset state. Using it as the address at which the GIC will be mapped into physical memory space can therefore be risky if it has not been initialised, since it may result in the GIC being mapped to an effectively random address anywhere in physical memory, where it might conflict with peripherals or RAM and lead to weird crashes. Since a "sane value" is very platform specific because it is particular to the platform's memory map, it is difficult to test for. At the very least, a warning message should be printed in the case that we trust the inherited value. Reported-by: Amit Kama <amit.kama@satixfy.com> Signed-off-by: Matt Redfearn <matt.redfearn@mips.com> Reviewed-by: Paul Burton <paul.burton@mips.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> --- drivers/irqchip/irq-mips-gic.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/irqchip') diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index 9b768899f07b..ef92a4d2038e 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -701,6 +701,8 @@ static int __init gic_of_init(struct device_node *node, gic_base = read_gcr_gic_base() & ~CM_GCR_GIC_BASE_GICEN; gic_len = 0x20000; + pr_warn("Using inherited base address %pa\n", + &gic_base); } else { pr_err("Failed to get memory range\n"); return -ENODEV; -- cgit