Commit 3a6ca8c5 authored by Linus Walleij's avatar Linus Walleij

ARM: plat-versatile: use simple irqdomain for FPGA IRQ

This switches the FPGA IRQ driver over to using the simple IRQ
domain. We can then use the same codepath for this in the
DT and non-DT cases.

To be able to use quicker irq_find_mapping() in the handlers
we first call irq_create_mapping() on all the valid HW IRQ
numbers so that descriptors will be created for them in the
DT case where a linear domain will be the outcome of the
call.
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 6f0c0580
/* /*
* Support for Versatile FPGA-based IRQ controllers * Support for Versatile FPGA-based IRQ controllers
*/ */
#include <linux/bitops.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
...@@ -117,13 +118,12 @@ static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq, ...@@ -117,13 +118,12 @@ static int fpga_irqdomain_map(struct irq_domain *d, unsigned int irq,
struct fpga_irq_data *f = d->host_data; struct fpga_irq_data *f = d->host_data;
/* Skip invalid IRQs, only register handlers for the real ones */ /* Skip invalid IRQs, only register handlers for the real ones */
if (!(f->valid & (1 << hwirq))) if (!(f->valid & BIT(hwirq)))
return -ENOTSUPP; return -ENOTSUPP;
irq_set_chip_data(irq, f); irq_set_chip_data(irq, f);
irq_set_chip_and_handler(irq, &f->chip, irq_set_chip_and_handler(irq, &f->chip,
handle_level_irq); handle_level_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
f->used_irqs++;
return 0; return 0;
} }
...@@ -132,13 +132,15 @@ static struct irq_domain_ops fpga_irqdomain_ops = { ...@@ -132,13 +132,15 @@ static struct irq_domain_ops fpga_irqdomain_ops = {
.xlate = irq_domain_xlate_onetwocell, .xlate = irq_domain_xlate_onetwocell,
}; };
static __init struct fpga_irq_data * void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) { int parent_irq, u32 valid, struct device_node *node)
{
struct fpga_irq_data *f; struct fpga_irq_data *f;
int i;
if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) { if (fpga_irq_id >= ARRAY_SIZE(fpga_irq_devices)) {
printk(KERN_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_PLAT_VERSATILE_FPGA_IRQ_NR\n", __func__);
return NULL; return;
} }
f = &fpga_irq_devices[fpga_irq_id]; f = &fpga_irq_devices[fpga_irq_id];
f->base = base; f->base = base;
...@@ -147,29 +149,28 @@ fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) { ...@@ -147,29 +149,28 @@ fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) {
f->chip.irq_mask = fpga_irq_mask; f->chip.irq_mask = fpga_irq_mask;
f->chip.irq_unmask = fpga_irq_unmask; f->chip.irq_unmask = fpga_irq_unmask;
f->valid = valid; f->valid = valid;
fpga_irq_id++;
return f;
}
void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
int parent_irq, u32 valid, struct device_node *node)
{
struct fpga_irq_data *f;
f = fpga_irq_prep_struct(base, name, valid);
if (!f)
return;
if (parent_irq != -1) { if (parent_irq != -1) {
irq_set_handler_data(parent_irq, f); irq_set_handler_data(parent_irq, f);
irq_set_chained_handler(parent_irq, fpga_irq_handle); irq_set_chained_handler(parent_irq, fpga_irq_handle);
} }
f->domain = irq_domain_add_legacy(node, fls(valid), irq_start, 0, /* This will also allocate irq descriptors */
f->domain = irq_domain_add_simple(node, fls(valid), irq_start,
&fpga_irqdomain_ops, f); &fpga_irqdomain_ops, f);
/* This will allocate all valid descriptors in the linear case */
for (i = 0; i < fls(valid); i++)
if (valid & BIT(i)) {
if (!irq_start)
irq_create_mapping(f->domain, i);
f->used_irqs++;
}
pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n", pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n",
fpga_irq_id, name, base, f->used_irqs); fpga_irq_id, name, base, f->used_irqs);
fpga_irq_id++;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -193,18 +194,11 @@ int __init fpga_irq_of_init(struct device_node *node, ...@@ -193,18 +194,11 @@ int __init fpga_irq_of_init(struct device_node *node,
if (of_property_read_u32(node, "valid-mask", &valid_mask)) if (of_property_read_u32(node, "valid-mask", &valid_mask))
valid_mask = 0; valid_mask = 0;
f = fpga_irq_prep_struct(base, node->name, valid_mask); fpga_irq_init(base, node->name, 0, -1, valid_mask, node);
if (!f)
return -ENOMEM;
writel(clear_mask, base + IRQ_ENABLE_CLEAR); writel(clear_mask, base + IRQ_ENABLE_CLEAR);
writel(clear_mask, base + FIQ_ENABLE_CLEAR); writel(clear_mask, base + FIQ_ENABLE_CLEAR);
f->domain = irq_domain_add_linear(node, fls(valid_mask), &fpga_irqdomain_ops, f);
f->used_irqs = hweight32(valid_mask);
pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n",
fpga_irq_id, node->name, base, f->used_irqs);
return 0; return 0;
} }
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment