Add a device tree binding for the FPGA SIC on versatile platforms. This also requires the addition of irq domain support for mapping to Linux IRQs.
Cc: Grant Likely <[email protected]> Cc: Rob Herring <[email protected]> Cc: Russell King <[email protected]> Signed-off-by: Jamie Iles <[email protected]> --- .../devicetree/bindings/arm/versatile-sic.txt | 27 ++++++++++ arch/arm/plat-versatile/Kconfig | 1 + arch/arm/plat-versatile/fpga-irq.c | 51 +++++++++++++++++++- arch/arm/plat-versatile/include/plat/fpga-irq.h | 6 ++ 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/versatile-sic.txt diff --git a/Documentation/devicetree/bindings/arm/versatile-sic.txt b/Documentation/devicetree/bindings/arm/versatile-sic.txt new file mode 100644 index 0000000..971a42e --- /dev/null +++ b/Documentation/devicetree/bindings/arm/versatile-sic.txt @@ -0,0 +1,27 @@ +* ARM Versatile FPGA Secondary Interrupt Controller + +The SIC is an interrupt controller embedded in an FPGA found on ARM versatile +platforms. + +Required properties: + +- compatible : "arm,versatile-sic" +- interrupt-controller : Identifies the node as an interrupt controller +- #interrupt-cells : The number of cells to define the interrupts. Must be 1 as + the SIC has no configuration options for interrupt sources. The cell is a u32 + and defines the interrupt number. +- reg : The register bank for the VIC. +- interrupt-parent : The interrupt controller that IRQ's are cascaded to. +- interrupts : Interrupt source for the interrupt that SIC IRQs are routed to + in the primary interrupt controller. + +Example: + + sic: intc@10003000 { + compatible = "arm,versatile-sic"; + interrupt-controller; + #interrupt-cells = <1>; + reg = <0x10003000 0x1000>; + interrupt-parent = <&vic>; + interrupts = <31>; + }; diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig index 52353be..a07ffe5 100644 --- a/arch/arm/plat-versatile/Kconfig +++ b/arch/arm/plat-versatile/Kconfig @@ -4,6 +4,7 @@ config PLAT_VERSATILE_CLCD bool config PLAT_VERSATILE_FPGA_IRQ + select IRQ_DOMAIN bool config PLAT_VERSATILE_LEDS diff --git a/arch/arm/plat-versatile/fpga-irq.c b/arch/arm/plat-versatile/fpga-irq.c index f0cc8e1..fd87b06 100644 --- a/arch/arm/plat-versatile/fpga-irq.c +++ b/arch/arm/plat-versatile/fpga-irq.c @@ -2,7 +2,13 @@ * Support for Versatile FPGA-based IRQ controllers */ #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/slab.h> #include <asm/mach/irq.h> #include <plat/fpga-irq.h> @@ -15,7 +21,7 @@ static void fpga_irq_mask(struct irq_data *d) { struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); - u32 mask = 1 << (d->irq - f->irq_start); + u32 mask = 1 << d->hwirq; writel(mask, f->base + IRQ_ENABLE_CLEAR); } @@ -23,7 +29,7 @@ static void fpga_irq_mask(struct irq_data *d) static void fpga_irq_unmask(struct irq_data *d) { struct fpga_irq_data *f = irq_data_get_irq_chip_data(d); - u32 mask = 1 << (d->irq - f->irq_start); + u32 mask = 1 << d->hwirq; writel(mask, f->base + IRQ_ENABLE_SET); } @@ -53,6 +59,10 @@ void __init fpga_irq_init(int parent_irq, u32 valid, struct fpga_irq_data *f) f->chip.irq_ack = fpga_irq_mask; f->chip.irq_mask = fpga_irq_mask; f->chip.irq_unmask = fpga_irq_unmask; + f->domain.irq_base = f->irq_start; + f->domain.nr_irq = 32; + f->domain.ops = &irq_domain_simple_ops; + irq_domain_add(&f->domain); if (parent_irq != -1) { irq_set_handler_data(parent_irq, f); @@ -70,3 +80,40 @@ void __init fpga_irq_init(int parent_irq, u32 valid, struct fpga_irq_data *f) } } } + +#ifdef CONFIG_OF +int __init sic_of_init(struct device_node *np, struct device_node *parent) +{ + struct fpga_irq_data *sic_data = kzalloc(sizeof(*sic_data), GFP_KERNEL); + int err = -ENOMEM, irq; + + if (WARN_ON(!sic_data)) + return err; + + sic_data->base = of_iomap(np, 0); + if (WARN_ON(!sic_data->base)) + goto out_free_data; + + irq = irq_of_parse_and_map(np, 0); + if (irq < 0) + goto out_free_data; + + sic_data->irq_start = irq_alloc_descs(-1, 0, 32, numa_node_id()); + if (WARN_ON(sic_data->irq_start < 0)) { + err = sic_data->irq_start; + goto out_unmap; + } + sic_data->domain.of_node = of_node_get(np); + + fpga_irq_init(irq, ~0, sic_data); + + return 0; + +out_unmap: + iounmap(sic_data->base); +out_free_data: + kfree(sic_data); + + return err; +} +#endif /* CONFIG_OF */ diff --git a/arch/arm/plat-versatile/include/plat/fpga-irq.h b/arch/arm/plat-versatile/include/plat/fpga-irq.h index 627fafd..a1391f3 100644 --- a/arch/arm/plat-versatile/include/plat/fpga-irq.h +++ b/arch/arm/plat-versatile/include/plat/fpga-irq.h @@ -1,12 +1,18 @@ #ifndef PLAT_FPGA_IRQ_H #define PLAT_FPGA_IRQ_H +#include <linux/irqdomain.h> + +struct device_node; + struct fpga_irq_data { void __iomem *base; unsigned int irq_start; struct irq_chip chip; + struct irq_domain domain; }; void fpga_irq_init(int, u32, struct fpga_irq_data *); +int sic_of_init(struct device_node *np, struct device_node *parent); #endif -- 1.7.5.4 _______________________________________________ devicetree-discuss mailing list [email protected] https://lists.ozlabs.org/listinfo/devicetree-discuss
