ARM: vic: device tree binding

This adds a device tree binding for the VIC based on the of_irq_init()
support.  This adds an irqdomain to the vic and always registers all
vics in the static vic array rather than for pm only to keep track of
the irq domain.  struct irq_data::hwirq is used where appropriate rather
than runtime masking.

v3:	- include linux/export.h for THIS_MODULE
v2:	- use irq_domain_simple_ops
	- remove stub implementation of vic_of_init for !CONFIG_OF
	- Make VIC select IRQ_DOMAIN

Reviewed-by: Rob Herring <robherring2@gmail.com>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
Tested-by: Thomas Abraham <thomas.abraham@linaro.org>
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
This commit is contained in:
Jamie Iles 2011-09-27 11:00:46 +01:00 committed by Marc Zyngier
parent 08d33b27f7
commit f9b28ccbc7
4 changed files with 116 additions and 30 deletions

View File

@ -0,0 +1,29 @@
* ARM Vectored Interrupt Controller
One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
system for interrupt routing. For multiple controllers they can either be
nested or have the outputs wire-OR'd together.
Required properties:
- compatible : should be one of
"arm,pl190-vic"
"arm,pl192-vic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : The number of cells to define the interrupts. Must be 1 as
the VIC has no configuration options for interrupt sources. The cell is a u32
and defines the interrupt number.
- reg : The register bank for the VIC.
Optional properties:
- interrupts : Interrupt source for parent controllers if the VIC is nested.
Example:
vic0: interrupt-controller@60000 {
compatible = "arm,pl192-vic";
interrupt-controller;
#interrupt-cells = <1>;
reg = <0x60000 0x1000>;
};

View File

@ -7,6 +7,7 @@ config GIC_NON_BANKED
bool bool
config ARM_VIC config ARM_VIC
select IRQ_DOMAIN
bool bool
config ARM_VIC_NR config ARM_VIC_NR

View File

@ -19,9 +19,14 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/export.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/syscore_ops.h> #include <linux/syscore_ops.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
@ -29,7 +34,6 @@
#include <asm/mach/irq.h> #include <asm/mach/irq.h>
#include <asm/hardware/vic.h> #include <asm/hardware/vic.h>
#ifdef CONFIG_PM
/** /**
* struct vic_device - VIC PM device * struct vic_device - VIC PM device
* @irq: The IRQ number for the base of the VIC. * @irq: The IRQ number for the base of the VIC.
@ -40,6 +44,7 @@
* @int_enable: Save for VIC_INT_ENABLE. * @int_enable: Save for VIC_INT_ENABLE.
* @soft_int: Save for VIC_INT_SOFT. * @soft_int: Save for VIC_INT_SOFT.
* @protect: Save for VIC_PROTECT. * @protect: Save for VIC_PROTECT.
* @domain: The IRQ domain for the VIC.
*/ */
struct vic_device { struct vic_device {
void __iomem *base; void __iomem *base;
@ -50,13 +55,13 @@ struct vic_device {
u32 int_enable; u32 int_enable;
u32 soft_int; u32 soft_int;
u32 protect; u32 protect;
struct irq_domain domain;
}; };
/* we cannot allocate memory when VICs are initially registered */ /* we cannot allocate memory when VICs are initially registered */
static struct vic_device vic_devices[CONFIG_ARM_VIC_NR]; static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
static int vic_id; static int vic_id;
#endif /* CONFIG_PM */
/** /**
* vic_init2 - common initialisation code * vic_init2 - common initialisation code
@ -156,39 +161,50 @@ static int __init vic_pm_init(void)
return 0; return 0;
} }
late_initcall(vic_pm_init); late_initcall(vic_pm_init);
#endif /* CONFIG_PM */
/** /**
* vic_pm_register - Register a VIC for later power management control * vic_register() - Register a VIC.
* @base: The base address of the VIC. * @base: The base address of the VIC.
* @irq: The base IRQ for the VIC. * @irq: The base IRQ for the VIC.
* @resume_sources: bitmask of interrupts allowed for resume sources. * @resume_sources: bitmask of interrupts allowed for resume sources.
* @node: The device tree node associated with the VIC.
* *
* Register the VIC with the system device tree so that it can be notified * Register the VIC with the system device tree so that it can be notified
* of suspend and resume requests and ensure that the correct actions are * of suspend and resume requests and ensure that the correct actions are
* taken to re-instate the settings on resume. * taken to re-instate the settings on resume.
*
* This also configures the IRQ domain for the VIC.
*/ */
static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources) static void __init vic_register(void __iomem *base, unsigned int irq,
u32 resume_sources, struct device_node *node)
{ {
struct vic_device *v; struct vic_device *v;
if (vic_id >= ARRAY_SIZE(vic_devices)) if (vic_id >= ARRAY_SIZE(vic_devices)) {
printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__); printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
else { return;
v = &vic_devices[vic_id];
v->base = base;
v->resume_sources = resume_sources;
v->irq = irq;
vic_id++;
} }
v = &vic_devices[vic_id];
v->base = base;
v->resume_sources = resume_sources;
v->irq = irq;
vic_id++;
v->domain.irq_base = irq;
v->domain.nr_irq = 32;
#ifdef CONFIG_OF_IRQ
v->domain.of_node = of_node_get(node);
v->domain.ops = &irq_domain_simple_ops;
#endif /* CONFIG_OF */
irq_domain_add(&v->domain);
} }
#else
static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
#endif /* CONFIG_PM */
static void vic_ack_irq(struct irq_data *d) static void vic_ack_irq(struct irq_data *d)
{ {
void __iomem *base = irq_data_get_irq_chip_data(d); void __iomem *base = irq_data_get_irq_chip_data(d);
unsigned int irq = d->irq & 31; unsigned int irq = d->hwirq;
writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
/* moreover, clear the soft-triggered, in case it was the reason */ /* moreover, clear the soft-triggered, in case it was the reason */
writel(1 << irq, base + VIC_INT_SOFT_CLEAR); writel(1 << irq, base + VIC_INT_SOFT_CLEAR);
@ -197,14 +213,14 @@ static void vic_ack_irq(struct irq_data *d)
static void vic_mask_irq(struct irq_data *d) static void vic_mask_irq(struct irq_data *d)
{ {
void __iomem *base = irq_data_get_irq_chip_data(d); void __iomem *base = irq_data_get_irq_chip_data(d);
unsigned int irq = d->irq & 31; unsigned int irq = d->hwirq;
writel(1 << irq, base + VIC_INT_ENABLE_CLEAR); writel(1 << irq, base + VIC_INT_ENABLE_CLEAR);
} }
static void vic_unmask_irq(struct irq_data *d) static void vic_unmask_irq(struct irq_data *d)
{ {
void __iomem *base = irq_data_get_irq_chip_data(d); void __iomem *base = irq_data_get_irq_chip_data(d);
unsigned int irq = d->irq & 31; unsigned int irq = d->hwirq;
writel(1 << irq, base + VIC_INT_ENABLE); writel(1 << irq, base + VIC_INT_ENABLE);
} }
@ -226,7 +242,7 @@ static struct vic_device *vic_from_irq(unsigned int irq)
static int vic_set_wake(struct irq_data *d, unsigned int on) static int vic_set_wake(struct irq_data *d, unsigned int on)
{ {
struct vic_device *v = vic_from_irq(d->irq); struct vic_device *v = vic_from_irq(d->irq);
unsigned int off = d->irq & 31; unsigned int off = d->hwirq;
u32 bit = 1 << off; u32 bit = 1 << off;
if (!v) if (!v)
@ -330,15 +346,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
vic_set_irq_sources(base, irq_start, vic_sources); vic_set_irq_sources(base, irq_start, vic_sources);
} }
/** static void __init __vic_init(void __iomem *base, unsigned int irq_start,
* vic_init - initialise a vectored interrupt controller u32 vic_sources, u32 resume_sources,
* @base: iomem base address struct device_node *node)
* @irq_start: starting interrupt number, must be muliple of 32
* @vic_sources: bitmask of interrupt sources to allow
* @resume_sources: bitmask of interrupt sources to allow for resume
*/
void __init vic_init(void __iomem *base, unsigned int irq_start,
u32 vic_sources, u32 resume_sources)
{ {
unsigned int i; unsigned int i;
u32 cellid = 0; u32 cellid = 0;
@ -375,5 +385,46 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
vic_set_irq_sources(base, irq_start, vic_sources); vic_set_irq_sources(base, irq_start, vic_sources);
vic_pm_register(base, irq_start, resume_sources); vic_register(base, irq_start, resume_sources, node);
} }
/**
* vic_init() - initialise a vectored interrupt controller
* @base: iomem base address
* @irq_start: starting interrupt number, must be muliple of 32
* @vic_sources: bitmask of interrupt sources to allow
* @resume_sources: bitmask of interrupt sources to allow for resume
*/
void __init vic_init(void __iomem *base, unsigned int irq_start,
u32 vic_sources, u32 resume_sources)
{
__vic_init(base, irq_start, vic_sources, resume_sources, NULL);
}
#ifdef CONFIG_OF
int __init vic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *regs;
int irq_base;
if (WARN(parent, "non-root VICs are not supported"))
return -EINVAL;
regs = of_iomap(node, 0);
if (WARN_ON(!regs))
return -EIO;
irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
if (WARN_ON(irq_base < 0))
goto out_unmap;
__vic_init(regs, irq_base, ~0, ~0, node);
return 0;
out_unmap:
iounmap(regs);
return -EIO;
}
#endif /* CONFIG OF */

View File

@ -41,7 +41,12 @@
#define VIC_PL192_VECT_ADDR 0xF00 #define VIC_PL192_VECT_ADDR 0xF00
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); #include <linux/compiler.h>
#endif #include <linux/types.h>
struct device_node;
void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
int vic_of_init(struct device_node *node, struct device_node *parent);
#endif /* __ASSEMBLY__ */
#endif #endif