Skip to content

Commit 9dc505d

Browse files
committed
Merge tag 'irqchip-4.15-3' of git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms into irq/core
Pull irqchip updates for 4.15, take #3 from Marc Zyngier: - New Socionext Synquacer EXIU driver - stm32 new platform support and fixes - One GICv4 bugfix - A couple of MIPS GIC cleanups
2 parents 722c908 + 666740f commit 9dc505d

File tree

9 files changed

+434
-55
lines changed

9 files changed

+434
-55
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
Socionext SynQuacer External Interrupt Unit (EXIU)
2+
3+
The Socionext Synquacer SoC has an external interrupt unit (EXIU)
4+
that forwards a block of 32 configurable input lines to 32 adjacent
5+
level-high type GICv3 SPIs.
6+
7+
Required properties:
8+
9+
- compatible : Should be "socionext,synquacer-exiu".
10+
- reg : Specifies base physical address and size of the
11+
control registers.
12+
- interrupt-controller : Identifies the node as an interrupt controller.
13+
- #interrupt-cells : Specifies the number of cells needed to encode an
14+
interrupt source. The value must be 3.
15+
- interrupt-parent : phandle of the GIC these interrupts are routed to.
16+
- socionext,spi-base : The SPI number of the first SPI of the 32 adjacent
17+
ones the EXIU forwards its interrups to.
18+
19+
Notes:
20+
21+
- Only SPIs can use the EXIU as an interrupt parent.
22+
23+
Example:
24+
25+
exiu: interrupt-controller@510c0000 {
26+
compatible = "socionext,synquacer-exiu";
27+
reg = <0x0 0x510c0000 0x0 0x20>;
28+
interrupt-controller;
29+
interrupt-parent = <&gic>;
30+
#interrupt-cells = <3>;
31+
socionext,spi-base = <112>;
32+
};

Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ STM32 External Interrupt Controller
22

33
Required properties:
44

5-
- compatible: Should be "st,stm32-exti"
5+
- compatible: Should be:
6+
"st,stm32-exti"
7+
"st,stm32h7-exti"
68
- reg: Specifies base physical address and size of the registers
79
- interrupt-controller: Indentifies the node as an interrupt controller
810
- #interrupt-cells: Specifies the number of cells to encode an interrupt

arch/arm64/Kconfig.platforms

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ config ARCH_SEATTLE
161161
config ARCH_SHMOBILE
162162
bool
163163

164+
config ARCH_SYNQUACER
165+
bool "Socionext SynQuacer SoC Family"
166+
164167
config ARCH_RENESAS
165168
bool "Renesas SoC Platforms"
166169
select ARCH_SHMOBILE

drivers/irqchip/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ config EZNPS_GIC
306306
config STM32_EXTI
307307
bool
308308
select IRQ_DOMAIN
309+
select GENERIC_IRQ_CHIP
309310

310311
config QCOM_IRQ_COMBINER
311312
bool "QCOM IRQ combiner support"

drivers/irqchip/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,5 @@ obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o irq-aspeed-i2c-ic.o
7979
obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o
8080
obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o
8181
obj-$(CONFIG_IRQ_UNIPHIER_AIDET) += irq-uniphier-aidet.o
82+
obj-$(CONFIG_ARCH_SYNQUACER) += irq-sni-exiu.o
8283
obj-$(CONFIG_MESON_IRQ_GPIO) += irq-meson-gpio.o

drivers/irqchip/irq-gic-v3-its.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2802,7 +2802,7 @@ static int its_vpe_irq_domain_activate(struct irq_domain *domain,
28022802

28032803
/* If we use the list map, we issue VMAPP on demand... */
28042804
if (its_list_map)
2805-
return true;
2805+
return 0;
28062806

28072807
/* Map the VPE to the first possible CPU */
28082808
vpe->col_idx = cpumask_first(cpu_online_mask);

drivers/irqchip/irq-mips-gic.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
* Copyright (C) 2008 Ralf Baechle ([email protected])
77
* Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved.
88
*/
9+
10+
#define pr_fmt(fmt) "irq-mips-gic: " fmt
11+
912
#include <linux/bitmap.h>
1013
#include <linux/clocksource.h>
1114
#include <linux/cpuhotplug.h>
@@ -685,7 +688,7 @@ static int __init gic_of_init(struct device_node *node,
685688

686689
cpu_vec = find_first_zero_bit(&reserved, hweight_long(ST0_IM));
687690
if (cpu_vec == hweight_long(ST0_IM)) {
688-
pr_err("No CPU vectors available for GIC\n");
691+
pr_err("No CPU vectors available\n");
689692
return -ENODEV;
690693
}
691694

@@ -698,8 +701,10 @@ static int __init gic_of_init(struct device_node *node,
698701
gic_base = read_gcr_gic_base() &
699702
~CM_GCR_GIC_BASE_GICEN;
700703
gic_len = 0x20000;
704+
pr_warn("Using inherited base address %pa\n",
705+
&gic_base);
701706
} else {
702-
pr_err("Failed to get GIC memory range\n");
707+
pr_err("Failed to get memory range\n");
703708
return -ENODEV;
704709
}
705710
} else {
@@ -757,7 +762,7 @@ static int __init gic_of_init(struct device_node *node,
757762
gic_shared_intrs, 0,
758763
&gic_irq_domain_ops, NULL);
759764
if (!gic_irq_domain) {
760-
pr_err("Failed to add GIC IRQ domain");
765+
pr_err("Failed to add IRQ domain");
761766
return -ENXIO;
762767
}
763768

@@ -766,7 +771,7 @@ static int __init gic_of_init(struct device_node *node,
766771
GIC_NUM_LOCAL_INTRS + gic_shared_intrs,
767772
node, &gic_ipi_domain_ops, NULL);
768773
if (!gic_ipi_domain) {
769-
pr_err("Failed to add GIC IPI domain");
774+
pr_err("Failed to add IPI domain");
770775
return -ENXIO;
771776
}
772777

drivers/irqchip/irq-sni-exiu.c

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
/*
2+
* Driver for Socionext External Interrupt Unit (EXIU)
3+
*
4+
* Copyright (c) 2017 Linaro, Ltd. <[email protected]>
5+
*
6+
* Based on irq-tegra.c:
7+
* Copyright (C) 2011 Google, Inc.
8+
* Copyright (C) 2010,2013, NVIDIA Corporation
9+
*
10+
* This program is free software; you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License version 2 as
12+
* published by the Free Software Foundation.
13+
*/
14+
15+
#include <linux/interrupt.h>
16+
#include <linux/io.h>
17+
#include <linux/irq.h>
18+
#include <linux/irqchip.h>
19+
#include <linux/irqdomain.h>
20+
#include <linux/of.h>
21+
#include <linux/of_address.h>
22+
#include <linux/of_irq.h>
23+
24+
#include <dt-bindings/interrupt-controller/arm-gic.h>
25+
26+
#define NUM_IRQS 32
27+
28+
#define EIMASK 0x00
29+
#define EISRCSEL 0x04
30+
#define EIREQSTA 0x08
31+
#define EIRAWREQSTA 0x0C
32+
#define EIREQCLR 0x10
33+
#define EILVL 0x14
34+
#define EIEDG 0x18
35+
#define EISIR 0x1C
36+
37+
struct exiu_irq_data {
38+
void __iomem *base;
39+
u32 spi_base;
40+
};
41+
42+
static void exiu_irq_eoi(struct irq_data *d)
43+
{
44+
struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
45+
46+
writel(BIT(d->hwirq), data->base + EIREQCLR);
47+
irq_chip_eoi_parent(d);
48+
}
49+
50+
static void exiu_irq_mask(struct irq_data *d)
51+
{
52+
struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
53+
u32 val;
54+
55+
val = readl_relaxed(data->base + EIMASK) | BIT(d->hwirq);
56+
writel_relaxed(val, data->base + EIMASK);
57+
irq_chip_mask_parent(d);
58+
}
59+
60+
static void exiu_irq_unmask(struct irq_data *d)
61+
{
62+
struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
63+
u32 val;
64+
65+
val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
66+
writel_relaxed(val, data->base + EIMASK);
67+
irq_chip_unmask_parent(d);
68+
}
69+
70+
static void exiu_irq_enable(struct irq_data *d)
71+
{
72+
struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
73+
u32 val;
74+
75+
/* clear interrupts that were latched while disabled */
76+
writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
77+
78+
val = readl_relaxed(data->base + EIMASK) & ~BIT(d->hwirq);
79+
writel_relaxed(val, data->base + EIMASK);
80+
irq_chip_enable_parent(d);
81+
}
82+
83+
static int exiu_irq_set_type(struct irq_data *d, unsigned int type)
84+
{
85+
struct exiu_irq_data *data = irq_data_get_irq_chip_data(d);
86+
u32 val;
87+
88+
val = readl_relaxed(data->base + EILVL);
89+
if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
90+
val |= BIT(d->hwirq);
91+
else
92+
val &= ~BIT(d->hwirq);
93+
writel_relaxed(val, data->base + EILVL);
94+
95+
val = readl_relaxed(data->base + EIEDG);
96+
if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
97+
val &= ~BIT(d->hwirq);
98+
else
99+
val |= BIT(d->hwirq);
100+
writel_relaxed(val, data->base + EIEDG);
101+
102+
writel_relaxed(BIT(d->hwirq), data->base + EIREQCLR);
103+
104+
return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
105+
}
106+
107+
static struct irq_chip exiu_irq_chip = {
108+
.name = "EXIU",
109+
.irq_eoi = exiu_irq_eoi,
110+
.irq_enable = exiu_irq_enable,
111+
.irq_mask = exiu_irq_mask,
112+
.irq_unmask = exiu_irq_unmask,
113+
.irq_set_type = exiu_irq_set_type,
114+
.irq_set_affinity = irq_chip_set_affinity_parent,
115+
.flags = IRQCHIP_SET_TYPE_MASKED |
116+
IRQCHIP_SKIP_SET_WAKE |
117+
IRQCHIP_EOI_THREADED |
118+
IRQCHIP_MASK_ON_SUSPEND,
119+
};
120+
121+
static int exiu_domain_translate(struct irq_domain *domain,
122+
struct irq_fwspec *fwspec,
123+
unsigned long *hwirq,
124+
unsigned int *type)
125+
{
126+
struct exiu_irq_data *info = domain->host_data;
127+
128+
if (is_of_node(fwspec->fwnode)) {
129+
if (fwspec->param_count != 3)
130+
return -EINVAL;
131+
132+
if (fwspec->param[0] != GIC_SPI)
133+
return -EINVAL; /* No PPI should point to this domain */
134+
135+
*hwirq = fwspec->param[1] - info->spi_base;
136+
*type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
137+
return 0;
138+
}
139+
return -EINVAL;
140+
}
141+
142+
static int exiu_domain_alloc(struct irq_domain *dom, unsigned int virq,
143+
unsigned int nr_irqs, void *data)
144+
{
145+
struct irq_fwspec *fwspec = data;
146+
struct irq_fwspec parent_fwspec;
147+
struct exiu_irq_data *info = dom->host_data;
148+
irq_hw_number_t hwirq;
149+
150+
if (fwspec->param_count != 3)
151+
return -EINVAL; /* Not GIC compliant */
152+
if (fwspec->param[0] != GIC_SPI)
153+
return -EINVAL; /* No PPI should point to this domain */
154+
155+
WARN_ON(nr_irqs != 1);
156+
hwirq = fwspec->param[1] - info->spi_base;
157+
irq_domain_set_hwirq_and_chip(dom, virq, hwirq, &exiu_irq_chip, info);
158+
159+
parent_fwspec = *fwspec;
160+
parent_fwspec.fwnode = dom->parent->fwnode;
161+
return irq_domain_alloc_irqs_parent(dom, virq, nr_irqs, &parent_fwspec);
162+
}
163+
164+
static const struct irq_domain_ops exiu_domain_ops = {
165+
.translate = exiu_domain_translate,
166+
.alloc = exiu_domain_alloc,
167+
.free = irq_domain_free_irqs_common,
168+
};
169+
170+
static int __init exiu_init(struct device_node *node,
171+
struct device_node *parent)
172+
{
173+
struct irq_domain *parent_domain, *domain;
174+
struct exiu_irq_data *data;
175+
int err;
176+
177+
if (!parent) {
178+
pr_err("%pOF: no parent, giving up\n", node);
179+
return -ENODEV;
180+
}
181+
182+
parent_domain = irq_find_host(parent);
183+
if (!parent_domain) {
184+
pr_err("%pOF: unable to obtain parent domain\n", node);
185+
return -ENXIO;
186+
}
187+
188+
data = kzalloc(sizeof(*data), GFP_KERNEL);
189+
if (!data)
190+
return -ENOMEM;
191+
192+
if (of_property_read_u32(node, "socionext,spi-base", &data->spi_base)) {
193+
pr_err("%pOF: failed to parse 'spi-base' property\n", node);
194+
err = -ENODEV;
195+
goto out_free;
196+
}
197+
198+
data->base = of_iomap(node, 0);
199+
if (IS_ERR(data->base)) {
200+
err = PTR_ERR(data->base);
201+
goto out_free;
202+
}
203+
204+
/* clear and mask all interrupts */
205+
writel_relaxed(0xFFFFFFFF, data->base + EIREQCLR);
206+
writel_relaxed(0xFFFFFFFF, data->base + EIMASK);
207+
208+
domain = irq_domain_add_hierarchy(parent_domain, 0, NUM_IRQS, node,
209+
&exiu_domain_ops, data);
210+
if (!domain) {
211+
pr_err("%pOF: failed to allocate domain\n", node);
212+
err = -ENOMEM;
213+
goto out_unmap;
214+
}
215+
216+
pr_info("%pOF: %d interrupts forwarded to %pOF\n", node, NUM_IRQS,
217+
parent);
218+
219+
return 0;
220+
221+
out_unmap:
222+
iounmap(data->base);
223+
out_free:
224+
kfree(data);
225+
return err;
226+
}
227+
IRQCHIP_DECLARE(exiu, "socionext,synquacer-exiu", exiu_init);

0 commit comments

Comments
 (0)