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>
This commit is contained in:
Родитель
2c88543b95
Коммит
9bc1503185
|
@ -0,0 +1,31 @@
|
|||
* ARM Versatile FPGA interrupt controller
|
||||
|
||||
One or more FPGA IRQ controllers can be synthesized in an ARM reference board
|
||||
such as the Integrator or Versatile family. The output of these different
|
||||
controllers are OR:ed together and fed to the CPU tile's IRQ input. Each
|
||||
instance can handle up to 32 interrupts.
|
||||
|
||||
Required properties:
|
||||
- compatible: "arm,versatile-fpga-irq"
|
||||
- interrupt-controller: Identifies the node as an interrupt controller
|
||||
- #interrupt-cells: The number of cells to define the interrupts. Must be 1
|
||||
as the FPGA IRQ controller has no configuration options for interrupt
|
||||
sources. The cell is a u32 and defines the interrupt number.
|
||||
- reg: The register bank for the FPGA interrupt controller.
|
||||
- clear-mask: a u32 number representing the mask written to clear all IRQs
|
||||
on the controller at boot for example.
|
||||
- valid-mask: a u32 number representing a bit mask determining which of
|
||||
the interrupts are valid. Unconnected/unused lines are set to 0, and
|
||||
the system till not make it possible for devices to request these
|
||||
interrupts.
|
||||
|
||||
Example:
|
||||
|
||||
pic: pic@14000000 {
|
||||
compatible = "arm,versatile-fpga-irq";
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-controller;
|
||||
reg = <0x14000000 0x100>;
|
||||
clear-mask = <0xffffffff>;
|
||||
valid-mask = <0x003fffff>;
|
||||
};
|
|
@ -5,6 +5,8 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
@ -14,11 +16,17 @@
|
|||
#define IRQ_RAW_STATUS 0x04
|
||||
#define IRQ_ENABLE_SET 0x08
|
||||
#define IRQ_ENABLE_CLEAR 0x0c
|
||||
#define INT_SOFT_SET 0x10
|
||||
#define INT_SOFT_CLEAR 0x14
|
||||
#define FIQ_STATUS 0x20
|
||||
#define FIQ_RAW_STATUS 0x24
|
||||
#define FIQ_ENABLE 0x28
|
||||
#define FIQ_ENABLE_SET 0x28
|
||||
#define FIQ_ENABLE_CLEAR 0x2C
|
||||
|
||||
/**
|
||||
* struct fpga_irq_data - irq data container for the FPGA IRQ controller
|
||||
* @base: memory offset in virtual memory
|
||||
* @irq_start: first IRQ number handled by this instance
|
||||
* @chip: chip container for this instance
|
||||
* @domain: IRQ domain for this instance
|
||||
* @valid: mask for valid IRQs on this controller
|
||||
|
@ -26,7 +34,6 @@
|
|||
*/
|
||||
struct fpga_irq_data {
|
||||
void __iomem *base;
|
||||
unsigned int irq_start;
|
||||
struct irq_chip chip;
|
||||
u32 valid;
|
||||
struct irq_domain *domain;
|
||||
|
@ -125,34 +132,79 @@ static struct irq_domain_ops fpga_irqdomain_ops = {
|
|||
.xlate = irq_domain_xlate_onetwocell,
|
||||
};
|
||||
|
||||
void __init fpga_irq_init(void __iomem *base, const char *name, int irq_start,
|
||||
int parent_irq, u32 valid, struct device_node *node)
|
||||
{
|
||||
static __init struct fpga_irq_data *
|
||||
fpga_irq_prep_struct(void __iomem *base, const char *name, u32 valid) {
|
||||
struct fpga_irq_data *f;
|
||||
|
||||
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__);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f = &fpga_irq_devices[fpga_irq_id];
|
||||
f->base = base;
|
||||
f->irq_start = irq_start;
|
||||
f->chip.name = name;
|
||||
f->chip.irq_ack = fpga_irq_mask;
|
||||
f->chip.irq_mask = fpga_irq_mask;
|
||||
f->chip.irq_unmask = fpga_irq_unmask;
|
||||
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) {
|
||||
irq_set_handler_data(parent_irq, f);
|
||||
irq_set_chained_handler(parent_irq, fpga_irq_handle);
|
||||
}
|
||||
|
||||
f->domain = irq_domain_add_legacy(node, fls(valid), f->irq_start, 0,
|
||||
f->domain = irq_domain_add_legacy(node, fls(valid), irq_start, 0,
|
||||
&fpga_irqdomain_ops, f);
|
||||
pr_info("FPGA IRQ chip %d \"%s\" @ %p, %u irqs\n",
|
||||
fpga_irq_id, name, base, f->used_irqs);
|
||||
|
||||
fpga_irq_id++;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
int __init fpga_irq_of_init(struct device_node *node,
|
||||
struct device_node *parent)
|
||||
{
|
||||
struct fpga_irq_data *f;
|
||||
void __iomem *base;
|
||||
u32 clear_mask;
|
||||
u32 valid_mask;
|
||||
|
||||
if (WARN_ON(!node))
|
||||
return -ENODEV;
|
||||
|
||||
base = of_iomap(node, 0);
|
||||
WARN(!base, "unable to map fpga irq registers\n");
|
||||
|
||||
if (of_property_read_u32(node, "clear-mask", &clear_mask))
|
||||
clear_mask = 0;
|
||||
|
||||
if (of_property_read_u32(node, "valid-mask", &valid_mask))
|
||||
valid_mask = 0;
|
||||
|
||||
f = fpga_irq_prep_struct(base, node->name, valid_mask);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
|
||||
writel(clear_mask, base + IRQ_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;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -7,5 +7,7 @@ struct pt_regs;
|
|||
void fpga_handle_irq(struct pt_regs *regs);
|
||||
void fpga_irq_init(void __iomem *, const char *, int, int, u32,
|
||||
struct device_node *node);
|
||||
int fpga_irq_of_init(struct device_node *node,
|
||||
struct device_node *parent);
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче