diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2012-09-06 04:07:57 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-09-17 18:18:18 -0400 |
commit | 9bc1503185a09930782012fda5601694caeec77a (patch) | |
tree | 12bf2ec9afc1e128ad63ad7b2382a590e4a0781e | |
parent | 2c88543b953581f70f05bf133a1b8f196c48ef23 (diff) |
ARM: 7516/1: plat-versatile: add DT support to FPGA IRQ
This adds Device Tree probing support to the Versatile FPGA
IRQ controller.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt | 31 | ||||
-rw-r--r-- | arch/arm/plat-versatile/fpga-irq.c | 72 | ||||
-rw-r--r-- | arch/arm/plat-versatile/include/plat/fpga-irq.h | 2 |
3 files changed, 95 insertions, 10 deletions
diff --git a/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt b/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt new file mode 100644 index 000000000000..9989eda755d9 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/versatile-fpga-irq.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | * ARM Versatile FPGA interrupt controller | ||
2 | |||
3 | One or more FPGA IRQ controllers can be synthesized in an ARM reference board | ||
4 | such as the Integrator or Versatile family. The output of these different | ||
5 | controllers are OR:ed together and fed to the CPU tile's IRQ input. Each | ||
6 | instance can handle up to 32 interrupts. | ||
7 | |||
8 | Required properties: | ||
9 | - compatible: "arm,versatile-fpga-irq" | ||
10 | - interrupt-controller: Identifies the node as an interrupt controller | ||
11 | - #interrupt-cells: The number of cells to define the interrupts. Must be 1 | ||
12 | as the FPGA IRQ controller has no configuration options for interrupt | ||
13 | sources. The cell is a u32 and defines the interrupt number. | ||
14 | - reg: The register bank for the FPGA interrupt controller. | ||
15 | - clear-mask: a u32 number representing the mask written to clear all IRQs | ||
16 | on the controller at boot for example. | ||
17 | - valid-mask: a u32 number representing a bit mask determining which of | ||
18 | the interrupts are valid. Unconnected/unused lines are set to 0, and | ||
19 | the system till not make it possible for devices to request these | ||
20 | interrupts. | ||
21 | |||
22 | Example: | ||
23 | |||
24 | pic: pic@14000000 { | ||
25 | compatible = "arm,versatile-fpga-irq"; | ||
26 | #interrupt-cells = <1>; | ||
27 | interrupt-controller; | ||
28 | reg = <0x14000000 0x100>; | ||
29 | clear-mask = <0xffffffff>; | ||
30 | valid-mask = <0x003fffff>; | ||
31 | }; | ||
diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c index 6e70d03824a1..091ae1030045 100644 --- a/arch/arm/plat-versatile/fpga-irq.c +++ b/arch/arm/plat-versatile/fpga-irq.c | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <linux/io.h> | 5 | #include <linux/io.h> |
6 | #include <linux/irqdomain.h> | 6 | #include <linux/irqdomain.h> |
7 | #include <linux/module.h> | 7 | #include <linux/module.h> |
8 | #include <linux/of.h> | ||
9 | #include <linux/of_address.h> | ||
8 | 10 | ||
9 | #include <asm/exception.h> | 11 | #include <asm/exception.h> |
10 | #include <asm/mach/irq.h> | 12 | #include <asm/mach/irq.h> |
@@ -14,11 +16,17 @@ | |||
14 | #define IRQ_RAW_STATUS 0x04 | 16 | #define IRQ_RAW_STATUS 0x04 |
15 | #define IRQ_ENABLE_SET 0x08 | 17 | #define IRQ_ENABLE_SET 0x08 |
16 | #define IRQ_ENABLE_CLEAR 0x0c | 18 | #define IRQ_ENABLE_CLEAR 0x0c |
19 | #define INT_SOFT_SET 0x10 | ||
20 | #define INT_SOFT_CLEAR 0x14 | ||
21 | #define FIQ_STATUS 0x20 | ||
22 | #define FIQ_RAW_STATUS 0x24 | ||
23 | #define FIQ_ENABLE 0x28 | ||
24 | #define FIQ_ENABLE_SET 0x28 | ||
25 | #define FIQ_ENABLE_CLEAR 0x2C | ||
17 | 26 | ||
18 | /** | 27 | /** |
19 | * struct fpga_irq_data - irq data container for the FPGA IRQ controller | 28 | * struct fpga_irq_data - irq data container for the FPGA IRQ controller |
20 | * @base: memory offset in virtual memory | 29 | * @base: memory offset in virtual memory |
21 | * @irq_start: first IRQ number handled by this instance | ||
22 | * @chip: chip container for this instance | 30 | * @chip: chip container for this instance |
23 | * @domain: IRQ domain for this instance | 31 | * @domain: IRQ domain for this instance |
24 | * @valid: mask for valid IRQs on this controller | 32 | * @valid: mask for valid IRQs on this controller |
@@ -26,7 +34,6 @@ | |||
26 | */ | 34 | */ |
27 | struct fpga_irq_data { | 35 | struct fpga_irq_data { |
28 | void __iomem *base; | 36 | void __iomem *base; |
29 | unsigned int irq_start; | ||
30 | struct irq_chip chip; | 37 | struct irq_chip chip; |
31 | u32 valid; | 38 | u32 valid; |
32 | struct irq_domain *domain; | 39 | struct irq_domain *domain; |
@@ -125,34 +132,79 @@ static struct irq_domain_ops fpga_irqdomain_ops = { | |||
125 | .xlate = irq_domain_xlate_onetwocell, | 132 | .xlate = irq_domain_xlate_onetwocell, |
126 | }; | 133 | }; |
127 | 134 | ||
128 | void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, | 135 | static __init struct fpga_irq_data * |
129 | int parent_irq, u32 valid, struct device_node *node) | 136 | fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) { |
130 | { | ||
131 | struct fpga_irq_data *f; | 137 | struct fpga_irq_data *f; |
132 | 138 | ||
133 | if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { | 139 | if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { |
134 | printk(KERN_ERR "%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); | 140 | printk(KERN_ERR "%s: too few FPGA IRQ controllers, increase CONFIG_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__); |
135 | return; | 141 | return NULL; |
136 | } | 142 | } |
137 | |||
138 | f = &fpga_irq_devices[fpga_irq_id]; | 143 | f = &fpga_irq_devices[fpga_irq_id]; |
139 | f->base = base; | 144 | f->base = base; |
140 | f->irq_start = irq_start; | ||
141 | f->chip.name = name; | 145 | f->chip.name = name; |
142 | f->chip.irq_ack = fpga_irq_mask; | 146 | f->chip.irq_ack = fpga_irq_mask; |
143 | f->chip.irq_mask = fpga_irq_mask; | 147 | f->chip.irq_mask = fpga_irq_mask; |
144 | f->chip.irq_unmask = fpga_irq_unmask; | 148 | f->chip.irq_unmask = fpga_irq_unmask; |
145 | f->valid = valid; | 149 | f->valid = valid; |
150 | fpga_irq_id++; | ||
151 | |||
152 | return f; | ||
153 | } | ||
154 | |||
155 | void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start, | ||
156 | int parent_irq, u32 valid, struct device_node *node) | ||
157 | { | ||
158 | struct fpga_irq_data *f; | ||
159 | |||
160 | f = fpga_irq_prep_struct(base, name, valid); | ||
161 | if (!f) | ||
162 | return; | ||
146 | 163 | ||
147 | if (parent_irq != -1) { | 164 | if (parent_irq != -1) { |
148 | irq_set_handler_data(parent_irq, f); | 165 | irq_set_handler_data(parent_irq, f); |
149 | irq_set_chained_handler(parent_irq, fpga_irq_handle); | 166 | irq_set_chained_handler(parent_irq, fpga_irq_handle); |
150 | } | 167 | } |
151 | 168 | ||
152 | f->domain = irq_domain_add_legacy(node, fls(valid), f->irq_start, 0, | 169 | f->domain = irq_domain_add_legacy(node, fls(valid), irq_start, 0, |
153 | &fpga_irqdomain_ops, f); | 170 | &fpga_irqdomain_ops, f); |
154 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", | 171 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", |
155 | fpga_irq_id, name, base, f->used_irqs); | 172 | fpga_irq_id, name, base, f->used_irqs); |
173 | } | ||
156 | 174 | ||
157 | fpga_irq_id++; | 175 | #ifdef CONFIG_OF |
176 | int __init fpga_irq_of_init(struct device_node *node, | ||
177 | struct device_node *parent) | ||
178 | { | ||
179 | struct fpga_irq_data *f; | ||
180 | void __iomem *base; | ||
181 | u32 clear_mask; | ||
182 | u32 valid_mask; | ||
183 | |||
184 | if (WARN_ON(!node)) | ||
185 | return -ENODEV; | ||
186 | |||
187 | base = of_iomap(node, 0); | ||
188 | WARN(!base, "unable to map fpga irq registers\n"); | ||
189 | |||
190 | if (of_property_read_u32(node, "clear-mask", &clear_mask)) | ||
191 | clear_mask = 0; | ||
192 | |||
193 | if (of_property_read_u32(node, "valid-mask", &valid_mask)) | ||
194 | valid_mask = 0; | ||
195 | |||
196 | f = fpga_irq_prep_struct(base, node->name, valid_mask); | ||
197 | if (!f) | ||
198 | return -ENOMEM; | ||
199 | |||
200 | writel(clear_mask, base + IRQ_ENABLE_CLEAR); | ||
201 | writel(clear_mask, base + FIQ_ENABLE_CLEAR); | ||
202 | |||
203 | f->domain = irq_domain_add_linear(node, fls(valid_mask), &fpga_irqdomain_ops, f); | ||
204 | f->used_irqs = hweight32(valid_mask); | ||
205 | |||
206 | pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", | ||
207 | fpga_irq_id, node->name, base, f->used_irqs); | ||
208 | return 0; | ||
158 | } | 209 | } |
210 | #endif | ||
diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h index 91bcfb67551d..1fac9651d3ca 100644 --- a/arch/arm/plat-versatile/include/plat/fpga-irq.h +++ b/arch/arm/plat-versatile/include/plat/fpga-irq.h | |||
@@ -7,5 +7,7 @@ struct pt_regs; | |||
7 | void fpga_handle_irq(struct pt_regs *regs); | 7 | void fpga_handle_irq(struct pt_regs *regs); |
8 | void fpga_irq_init(void __iomem *, const char *, int, int, u32, | 8 | void fpga_irq_init(void __iomem *, const char *, int, int, u32, |
9 | struct device_node *node); | 9 | struct device_node *node); |
10 | int fpga_irq_of_init(struct device_node *node, | ||
11 | struct device_node *parent); | ||
10 | 12 | ||
11 | #endif | 13 | #endif |