mirror of
https://github.com/torvalds/linux.git
synced 2024-10-24 06:01:01 +00:00
ARM: gic: add OF based initialization
This adds ARM gic interrupt controller initialization using device tree data. The initialization function is intended to be called by of_irq_init function like this: const static struct of_device_id irq_match[] = { { .compatible = "arm,cortex-a9-gic", .data = gic_of_init, }, {} }; static void __init init_irqs(void) { of_irq_init(irq_match); } Signed-off-by: Rob Herring <rob.herring@calxeda.com> Reviewed-by: Jamie Iles <jamie@jamieiles.com> Tested-by: Thomas Abraham <thomas.abraham@linaro.org> Acked-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
parent
4294f8baaf
commit
b3f7ed0324
55
Documentation/devicetree/bindings/arm/gic.txt
Normal file
55
Documentation/devicetree/bindings/arm/gic.txt
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
* ARM Generic Interrupt Controller
|
||||||
|
|
||||||
|
ARM SMP cores are often associated with a GIC, providing per processor
|
||||||
|
interrupts (PPI), shared processor interrupts (SPI) and software
|
||||||
|
generated interrupts (SGI).
|
||||||
|
|
||||||
|
Primary GIC is attached directly to the CPU and typically has PPIs and SGIs.
|
||||||
|
Secondary GICs are cascaded into the upward interrupt controller and do not
|
||||||
|
have PPIs or SGIs.
|
||||||
|
|
||||||
|
Main node required properties:
|
||||||
|
|
||||||
|
- compatible : should be one of:
|
||||||
|
"arm,cortex-a9-gic"
|
||||||
|
"arm,arm11mp-gic"
|
||||||
|
- interrupt-controller : Identifies the node as an interrupt controller
|
||||||
|
- #interrupt-cells : Specifies the number of cells needed to encode an
|
||||||
|
interrupt source. The type shall be a <u32> and the value shall be 3.
|
||||||
|
|
||||||
|
The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI
|
||||||
|
interrupts.
|
||||||
|
|
||||||
|
The 2nd cell contains the interrupt number for the interrupt type.
|
||||||
|
SPI interrupts are in the range [0-987]. PPI interrupts are in the
|
||||||
|
range [0-15].
|
||||||
|
|
||||||
|
The 3rd cell is the flags, encoded as follows:
|
||||||
|
bits[3:0] trigger type and level flags.
|
||||||
|
1 = low-to-high edge triggered
|
||||||
|
2 = high-to-low edge triggered
|
||||||
|
4 = active high level-sensitive
|
||||||
|
8 = active low level-sensitive
|
||||||
|
bits[15:8] PPI interrupt cpu mask. Each bit corresponds to each of
|
||||||
|
the 8 possible cpus attached to the GIC. A bit set to '1' indicated
|
||||||
|
the interrupt is wired to that CPU. Only valid for PPI interrupts.
|
||||||
|
|
||||||
|
- reg : Specifies base physical address(s) and size of the GIC registers. The
|
||||||
|
first region is the GIC distributor register base and size. The 2nd region is
|
||||||
|
the GIC cpu interface register base and size.
|
||||||
|
|
||||||
|
Optional
|
||||||
|
- interrupts : Interrupt source of the parent interrupt controller. Only
|
||||||
|
present on secondary GICs.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
intc: interrupt-controller@fff11000 {
|
||||||
|
compatible = "arm,cortex-a9-gic";
|
||||||
|
#interrupt-cells = <3>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
interrupt-controller;
|
||||||
|
reg = <0xfff11000 0x1000>,
|
||||||
|
<0xfff10100 0x100>;
|
||||||
|
};
|
||||||
|
|
|
@ -30,6 +30,9 @@
|
||||||
#include <linux/cpu_pm.h>
|
#include <linux/cpu_pm.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
#include <linux/irqdomain.h>
|
#include <linux/irqdomain.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/percpu.h>
|
#include <linux/percpu.h>
|
||||||
|
@ -530,7 +533,33 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static int gic_irq_domain_dt_translate(struct irq_domain *d,
|
||||||
|
struct device_node *controller,
|
||||||
|
const u32 *intspec, unsigned int intsize,
|
||||||
|
unsigned long *out_hwirq, unsigned int *out_type)
|
||||||
|
{
|
||||||
|
if (d->of_node != controller)
|
||||||
|
return -EINVAL;
|
||||||
|
if (intsize < 3)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* Get the interrupt number and add 16 to skip over SGIs */
|
||||||
|
*out_hwirq = intspec[1] + 16;
|
||||||
|
|
||||||
|
/* For SPIs, we need to add 16 more to get the GIC irq ID number */
|
||||||
|
if (!intspec[0])
|
||||||
|
*out_hwirq += 16;
|
||||||
|
|
||||||
|
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
const struct irq_domain_ops gic_irq_domain_ops = {
|
const struct irq_domain_ops gic_irq_domain_ops = {
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
.dt_translate = gic_irq_domain_dt_translate,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
|
void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
|
||||||
|
@ -608,3 +637,35 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
|
||||||
writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
|
writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static int gic_cnt __initdata = 0;
|
||||||
|
|
||||||
|
int __init gic_of_init(struct device_node *node, struct device_node *parent)
|
||||||
|
{
|
||||||
|
void __iomem *cpu_base;
|
||||||
|
void __iomem *dist_base;
|
||||||
|
int irq;
|
||||||
|
struct irq_domain *domain = &gic_data[gic_cnt].domain;
|
||||||
|
|
||||||
|
if (WARN_ON(!node))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
dist_base = of_iomap(node, 0);
|
||||||
|
WARN(!dist_base, "unable to map gic dist registers\n");
|
||||||
|
|
||||||
|
cpu_base = of_iomap(node, 1);
|
||||||
|
WARN(!cpu_base, "unable to map gic cpu registers\n");
|
||||||
|
|
||||||
|
domain->of_node = of_node_get(node);
|
||||||
|
|
||||||
|
gic_init(gic_cnt, 16, dist_base, cpu_base);
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
irq = irq_of_parse_and_map(node, 0);
|
||||||
|
gic_cascade_irq(gic_cnt, irq);
|
||||||
|
}
|
||||||
|
gic_cnt++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -40,6 +40,7 @@ extern void __iomem *gic_cpu_base_addr;
|
||||||
extern struct irq_chip gic_arch_extn;
|
extern struct irq_chip gic_arch_extn;
|
||||||
|
|
||||||
void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
|
void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
|
||||||
|
int gic_of_init(struct device_node *node, struct device_node *parent);
|
||||||
void gic_secondary_init(unsigned int);
|
void gic_secondary_init(unsigned int);
|
||||||
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
|
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
|
||||||
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
|
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user