Add support for GIC crossbar that routes interrupts on newer omaps.
Looks like people wanted these merged via the omap tree as it's the only user for the GIC crossbar. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.15 (GNU/Linux) iQIcBAABAgAGBQJTE7tJAAoJEBvUPslcq6VzdnQP/i+SLcdTcG6osw8mSoiodK3n BC2/ByQBzI5Q2u3CrISqayPX7lpCP4XWABJ9eEYOC9S5CVda7SjW3nobH764HBre 7y5fRg2OV5kRZZbvS66akcuMys2iwS3ExTZfn6W1ZKgIckqd0t2Q/7ds3mrgVFwv NzI5qEgHjHyNW2dNaVqW+7RblXbyRi8A1VGZofVduBbS2bxq7GPUWNM6CaFYW7aK 8ioYo6sMATUztvqCI/JbNnIWUZV/pfgZXeBYuO5nWgxY/EVd+m2CBMaBKD2bP+Z7 gdzRGEpVqKMZzeo8E10vJML0cLVq53PfBnobEjXFFXgR2Lt63KOsgZov4iHmIIrH FAccTryFfcsD30yunygPLjyYYsOcQEgMGK4aSRiGfmKJS5fxKgIaeBcr8wL9x3ac k3oThe9c19O2jt+sLN0ZVrG7y59th3t4a+mZ9AMFIEjrFm7ExDZ+NOhyLfx7LKsM dKO+FD0sXsRgCdFZXgC/nmSgE9t3pqKotTrPthZY3rivZan0mspdIJzkaU7TEqSw EqThl55cqpexlUfB7YwxsfmJ7y1O2Bxk3ShGhxZ+Wwfhgm8QDeH8VEaACfmkSukq NaNAYdi2yEV8HydXgsd5XhBazGN2ju3fT+/gqFjOKqT8zJrJI7QkDiNH1QcOTTAb XbKBumhC3ClwyFNlfhvx =MLEE -----END PGP SIGNATURE----- Merge tag 'omap-for-v3.15/crossbar-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into next/drivers Merge OMAP crossbar support from Tony Lindgren: Add support for GIC crossbar that routes interrupts on newer omaps. Looks like people wanted these merged via the omap tree as it's the only user for the GIC crossbar. * tag 'omap-for-v3.15/crossbar-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: ARM: DRA: Enable Crossbar IP support for DRA7XX ARM: OMAP4+: Correct Wakeup-gen code to use physical irq number DRIVERS: IRQCHIP: CROSSBAR: Add support for Crossbar IP DRIVERS: IRQCHIP: IRQ-GIC: Add support for routable irqs Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
63261d76c8
@ -50,6 +50,11 @@ Optional
|
|||||||
regions, used when the GIC doesn't have banked registers. The offset is
|
regions, used when the GIC doesn't have banked registers. The offset is
|
||||||
cpu-offset * cpu-nr.
|
cpu-offset * cpu-nr.
|
||||||
|
|
||||||
|
- arm,routable-irqs : Total number of gic irq inputs which are not directly
|
||||||
|
connected from the peripherals, but are routed dynamically
|
||||||
|
by a crossbar/multiplexer preceding the GIC. The GIC irq
|
||||||
|
input line is assigned dynamically when the corresponding
|
||||||
|
peripheral's crossbar line is mapped.
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
intc: interrupt-controller@fff11000 {
|
intc: interrupt-controller@fff11000 {
|
||||||
@ -57,6 +62,7 @@ Example:
|
|||||||
#interrupt-cells = <3>;
|
#interrupt-cells = <3>;
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
interrupt-controller;
|
interrupt-controller;
|
||||||
|
arm,routable-irqs = <160>;
|
||||||
reg = <0xfff11000 0x1000>,
|
reg = <0xfff11000 0x1000>,
|
||||||
<0xfff10100 0x100>;
|
<0xfff10100 0x100>;
|
||||||
};
|
};
|
||||||
|
27
Documentation/devicetree/bindings/arm/omap/crossbar.txt
Normal file
27
Documentation/devicetree/bindings/arm/omap/crossbar.txt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Some socs have a large number of interrupts requests to service
|
||||||
|
the needs of its many peripherals and subsystems. All of the
|
||||||
|
interrupt lines from the subsystems are not needed at the same
|
||||||
|
time, so they have to be muxed to the irq-controller appropriately.
|
||||||
|
In such places a interrupt controllers are preceded by an CROSSBAR
|
||||||
|
that provides flexibility in muxing the device requests to the controller
|
||||||
|
inputs.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible : Should be "ti,irq-crossbar"
|
||||||
|
- reg: Base address and the size of the crossbar registers.
|
||||||
|
- ti,max-irqs: Total number of irqs available at the interrupt controller.
|
||||||
|
- ti,reg-size: Size of a individual register in bytes. Every individual
|
||||||
|
register is assumed to be of same size. Valid sizes are 1, 2, 4.
|
||||||
|
- ti,irqs-reserved: List of the reserved irq lines that are not muxed using
|
||||||
|
crossbar. These interrupt lines are reserved in the soc,
|
||||||
|
so crossbar bar driver should not consider them as free
|
||||||
|
lines.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
crossbar_mpu: @4a020000 {
|
||||||
|
compatible = "ti,irq-crossbar";
|
||||||
|
reg = <0x4a002a48 0x130>;
|
||||||
|
ti,max-irqs = <160>;
|
||||||
|
ti,reg-size = <2>;
|
||||||
|
ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>;
|
||||||
|
};
|
@ -85,6 +85,7 @@ config SOC_DRA7XX
|
|||||||
select CPU_V7
|
select CPU_V7
|
||||||
select HAVE_SMP
|
select HAVE_SMP
|
||||||
select HAVE_ARM_ARCH_TIMER
|
select HAVE_ARM_ARCH_TIMER
|
||||||
|
select IRQ_CROSSBAR
|
||||||
|
|
||||||
config ARCH_OMAP2PLUS
|
config ARCH_OMAP2PLUS
|
||||||
bool
|
bool
|
||||||
|
@ -138,7 +138,7 @@ static void wakeupgen_mask(struct irq_data *d)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&wakeupgen_lock, flags);
|
raw_spin_lock_irqsave(&wakeupgen_lock, flags);
|
||||||
_wakeupgen_clear(d->irq, irq_target_cpu[d->irq]);
|
_wakeupgen_clear(d->hwirq, irq_target_cpu[d->hwirq]);
|
||||||
raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
|
raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ static void wakeupgen_unmask(struct irq_data *d)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&wakeupgen_lock, flags);
|
raw_spin_lock_irqsave(&wakeupgen_lock, flags);
|
||||||
_wakeupgen_set(d->irq, irq_target_cpu[d->irq]);
|
_wakeupgen_set(d->hwirq, irq_target_cpu[d->hwirq]);
|
||||||
raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
|
raw_spin_unlock_irqrestore(&wakeupgen_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/irqchip/arm-gic.h>
|
#include <linux/irqchip/arm-gic.h>
|
||||||
|
#include <linux/irqchip/irq-crossbar.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
@ -288,5 +289,8 @@ void __init omap_gic_of_init(void)
|
|||||||
|
|
||||||
skip_errata_init:
|
skip_errata_init:
|
||||||
omap_wakeupgen_init();
|
omap_wakeupgen_init();
|
||||||
|
#ifdef CONFIG_IRQ_CROSSBAR
|
||||||
|
irqcrossbar_init();
|
||||||
|
#endif
|
||||||
irqchip_init();
|
irqchip_init();
|
||||||
}
|
}
|
||||||
|
@ -69,3 +69,11 @@ config VERSATILE_FPGA_IRQ_NR
|
|||||||
config XTENSA_MX
|
config XTENSA_MX
|
||||||
bool
|
bool
|
||||||
select IRQ_DOMAIN
|
select IRQ_DOMAIN
|
||||||
|
|
||||||
|
config IRQ_CROSSBAR
|
||||||
|
bool
|
||||||
|
help
|
||||||
|
Support for a CROSSBAR ip that preceeds the main interrupt controller.
|
||||||
|
The primary irqchip invokes the crossbar's callback which inturn allocates
|
||||||
|
a free irq and configures the IP. Thus the peripheral interrupts are
|
||||||
|
routed to one of the free irqchip interrupt lines.
|
||||||
|
@ -26,3 +26,4 @@ obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
|
|||||||
obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
|
obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
|
||||||
obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
|
obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
|
||||||
obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
|
obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
|
||||||
|
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
|
||||||
|
208
drivers/irqchip/irq-crossbar.c
Normal file
208
drivers/irqchip/irq-crossbar.c
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* drivers/irqchip/irq-crossbar.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
|
||||||
|
* Author: Sricharan R <r.sricharan@ti.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_irq.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/irqchip/arm-gic.h>
|
||||||
|
|
||||||
|
#define IRQ_FREE -1
|
||||||
|
#define GIC_IRQ_START 32
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @int_max: maximum number of supported interrupts
|
||||||
|
* @irq_map: array of interrupts to crossbar number mapping
|
||||||
|
* @crossbar_base: crossbar base address
|
||||||
|
* @register_offsets: offsets for each irq number
|
||||||
|
*/
|
||||||
|
struct crossbar_device {
|
||||||
|
uint int_max;
|
||||||
|
uint *irq_map;
|
||||||
|
void __iomem *crossbar_base;
|
||||||
|
int *register_offsets;
|
||||||
|
void (*write) (int, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct crossbar_device *cb;
|
||||||
|
|
||||||
|
static inline void crossbar_writel(int irq_no, int cb_no)
|
||||||
|
{
|
||||||
|
writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void crossbar_writew(int irq_no, int cb_no)
|
||||||
|
{
|
||||||
|
writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void crossbar_writeb(int irq_no, int cb_no)
|
||||||
|
{
|
||||||
|
writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int allocate_free_irq(int cb_no)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < cb->int_max; i++) {
|
||||||
|
if (cb->irq_map[i] == IRQ_FREE) {
|
||||||
|
cb->irq_map[i] = cb_no;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crossbar_domain_map(struct irq_domain *d, unsigned int irq,
|
||||||
|
irq_hw_number_t hw)
|
||||||
|
{
|
||||||
|
cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq)
|
||||||
|
{
|
||||||
|
irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq;
|
||||||
|
|
||||||
|
if (hw > GIC_IRQ_START)
|
||||||
|
cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int crossbar_domain_xlate(struct irq_domain *d,
|
||||||
|
struct device_node *controller,
|
||||||
|
const u32 *intspec, unsigned int intsize,
|
||||||
|
unsigned long *out_hwirq,
|
||||||
|
unsigned int *out_type)
|
||||||
|
{
|
||||||
|
unsigned long ret;
|
||||||
|
|
||||||
|
ret = allocate_free_irq(intspec[1]);
|
||||||
|
|
||||||
|
if (IS_ERR_VALUE(ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*out_hwirq = ret + GIC_IRQ_START;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct irq_domain_ops routable_irq_domain_ops = {
|
||||||
|
.map = crossbar_domain_map,
|
||||||
|
.unmap = crossbar_domain_unmap,
|
||||||
|
.xlate = crossbar_domain_xlate
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init crossbar_of_init(struct device_node *node)
|
||||||
|
{
|
||||||
|
int i, size, max, reserved = 0, entry;
|
||||||
|
const __be32 *irqsr;
|
||||||
|
|
||||||
|
cb = kzalloc(sizeof(struct cb_device *), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!cb)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
cb->crossbar_base = of_iomap(node, 0);
|
||||||
|
if (!cb->crossbar_base)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
|
of_property_read_u32(node, "ti,max-irqs", &max);
|
||||||
|
cb->irq_map = kzalloc(max * sizeof(int), GFP_KERNEL);
|
||||||
|
if (!cb->irq_map)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
cb->int_max = max;
|
||||||
|
|
||||||
|
for (i = 0; i < max; i++)
|
||||||
|
cb->irq_map[i] = IRQ_FREE;
|
||||||
|
|
||||||
|
/* Get and mark reserved irqs */
|
||||||
|
irqsr = of_get_property(node, "ti,irqs-reserved", &size);
|
||||||
|
if (irqsr) {
|
||||||
|
size /= sizeof(__be32);
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
of_property_read_u32_index(node,
|
||||||
|
"ti,irqs-reserved",
|
||||||
|
i, &entry);
|
||||||
|
if (entry > max) {
|
||||||
|
pr_err("Invalid reserved entry\n");
|
||||||
|
goto err3;
|
||||||
|
}
|
||||||
|
cb->irq_map[entry] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb->register_offsets = kzalloc(max * sizeof(int), GFP_KERNEL);
|
||||||
|
if (!cb->register_offsets)
|
||||||
|
goto err3;
|
||||||
|
|
||||||
|
of_property_read_u32(node, "ti,reg-size", &size);
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case 1:
|
||||||
|
cb->write = crossbar_writeb;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cb->write = crossbar_writew;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
cb->write = crossbar_writel;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pr_err("Invalid reg-size property\n");
|
||||||
|
goto err4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Register offsets are not linear because of the
|
||||||
|
* reserved irqs. so find and store the offsets once.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < max; i++) {
|
||||||
|
if (!cb->irq_map[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cb->register_offsets[i] = reserved;
|
||||||
|
reserved += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
register_routable_domain_ops(&routable_irq_domain_ops);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err4:
|
||||||
|
kfree(cb->register_offsets);
|
||||||
|
err3:
|
||||||
|
kfree(cb->irq_map);
|
||||||
|
err2:
|
||||||
|
iounmap(cb->crossbar_base);
|
||||||
|
err1:
|
||||||
|
kfree(cb);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id crossbar_match[] __initconst = {
|
||||||
|
{ .compatible = "ti,irq-crossbar" },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
int __init irqcrossbar_init(void)
|
||||||
|
{
|
||||||
|
struct device_node *np;
|
||||||
|
np = of_find_matching_node(NULL, crossbar_match);
|
||||||
|
if (!np)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
crossbar_of_init(np);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -824,16 +824,25 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
|||||||
irq_set_chip_and_handler(irq, &gic_chip,
|
irq_set_chip_and_handler(irq, &gic_chip,
|
||||||
handle_fasteoi_irq);
|
handle_fasteoi_irq);
|
||||||
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||||
|
|
||||||
|
gic_routable_irq_domain_ops->map(d, irq, hw);
|
||||||
}
|
}
|
||||||
irq_set_chip_data(irq, d->host_data);
|
irq_set_chip_data(irq, d->host_data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
|
||||||
|
{
|
||||||
|
gic_routable_irq_domain_ops->unmap(d, irq);
|
||||||
|
}
|
||||||
|
|
||||||
static int gic_irq_domain_xlate(struct irq_domain *d,
|
static int gic_irq_domain_xlate(struct irq_domain *d,
|
||||||
struct device_node *controller,
|
struct device_node *controller,
|
||||||
const u32 *intspec, unsigned int intsize,
|
const u32 *intspec, unsigned int intsize,
|
||||||
unsigned long *out_hwirq, unsigned int *out_type)
|
unsigned long *out_hwirq, unsigned int *out_type)
|
||||||
{
|
{
|
||||||
|
unsigned long ret = 0;
|
||||||
|
|
||||||
if (d->of_node != controller)
|
if (d->of_node != controller)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (intsize < 3)
|
if (intsize < 3)
|
||||||
@ -843,11 +852,20 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
|
|||||||
*out_hwirq = intspec[1] + 16;
|
*out_hwirq = intspec[1] + 16;
|
||||||
|
|
||||||
/* For SPIs, we need to add 16 more to get the GIC irq ID number */
|
/* For SPIs, we need to add 16 more to get the GIC irq ID number */
|
||||||
if (!intspec[0])
|
if (!intspec[0]) {
|
||||||
*out_hwirq += 16;
|
ret = gic_routable_irq_domain_ops->xlate(d, controller,
|
||||||
|
intspec,
|
||||||
|
intsize,
|
||||||
|
out_hwirq,
|
||||||
|
out_type);
|
||||||
|
|
||||||
|
if (IS_ERR_VALUE(ret))
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
|
*out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
|
||||||
return 0;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
@ -871,9 +889,41 @@ static struct notifier_block gic_cpu_notifier = {
|
|||||||
|
|
||||||
const struct irq_domain_ops gic_irq_domain_ops = {
|
const struct irq_domain_ops gic_irq_domain_ops = {
|
||||||
.map = gic_irq_domain_map,
|
.map = gic_irq_domain_map,
|
||||||
|
.unmap = gic_irq_domain_unmap,
|
||||||
.xlate = gic_irq_domain_xlate,
|
.xlate = gic_irq_domain_xlate,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Default functions for routable irq domain */
|
||||||
|
static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq,
|
||||||
|
irq_hw_number_t hw)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gic_routable_irq_domain_unmap(struct irq_domain *d,
|
||||||
|
unsigned int irq)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static int gic_routable_irq_domain_xlate(struct irq_domain *d,
|
||||||
|
struct device_node *controller,
|
||||||
|
const u32 *intspec, unsigned int intsize,
|
||||||
|
unsigned long *out_hwirq,
|
||||||
|
unsigned int *out_type)
|
||||||
|
{
|
||||||
|
*out_hwirq += 16;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct irq_domain_ops gic_default_routable_irq_domain_ops = {
|
||||||
|
.map = gic_routable_irq_domain_map,
|
||||||
|
.unmap = gic_routable_irq_domain_unmap,
|
||||||
|
.xlate = gic_routable_irq_domain_xlate,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct irq_domain_ops *gic_routable_irq_domain_ops =
|
||||||
|
&gic_default_routable_irq_domain_ops;
|
||||||
|
|
||||||
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
||||||
void __iomem *dist_base, void __iomem *cpu_base,
|
void __iomem *dist_base, void __iomem *cpu_base,
|
||||||
u32 percpu_offset, struct device_node *node)
|
u32 percpu_offset, struct device_node *node)
|
||||||
@ -881,6 +931,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
|||||||
irq_hw_number_t hwirq_base;
|
irq_hw_number_t hwirq_base;
|
||||||
struct gic_chip_data *gic;
|
struct gic_chip_data *gic;
|
||||||
int gic_irqs, irq_base, i;
|
int gic_irqs, irq_base, i;
|
||||||
|
int nr_routable_irqs;
|
||||||
|
|
||||||
BUG_ON(gic_nr >= MAX_GIC_NR);
|
BUG_ON(gic_nr >= MAX_GIC_NR);
|
||||||
|
|
||||||
@ -946,14 +997,25 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
|
|||||||
gic->gic_irqs = gic_irqs;
|
gic->gic_irqs = gic_irqs;
|
||||||
|
|
||||||
gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
|
gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
|
||||||
irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
|
|
||||||
if (IS_ERR_VALUE(irq_base)) {
|
if (of_property_read_u32(node, "arm,routable-irqs",
|
||||||
WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
|
&nr_routable_irqs)) {
|
||||||
irq_start);
|
irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
|
||||||
irq_base = irq_start;
|
numa_node_id());
|
||||||
|
if (IS_ERR_VALUE(irq_base)) {
|
||||||
|
WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
|
||||||
|
irq_start);
|
||||||
|
irq_base = irq_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
|
||||||
|
hwirq_base, &gic_irq_domain_ops, gic);
|
||||||
|
} else {
|
||||||
|
gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
|
||||||
|
&gic_irq_domain_ops,
|
||||||
|
gic);
|
||||||
}
|
}
|
||||||
gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
|
|
||||||
hwirq_base, &gic_irq_domain_ops, gic);
|
|
||||||
if (WARN_ON(!gic->domain))
|
if (WARN_ON(!gic->domain))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -93,6 +93,11 @@ int gic_get_cpu_id(unsigned int cpu);
|
|||||||
void gic_migrate_target(unsigned int new_cpu_id);
|
void gic_migrate_target(unsigned int new_cpu_id);
|
||||||
unsigned long gic_get_sgir_physaddr(void);
|
unsigned long gic_get_sgir_physaddr(void);
|
||||||
|
|
||||||
|
extern const struct irq_domain_ops *gic_routable_irq_domain_ops;
|
||||||
|
static inline void __init register_routable_domain_ops
|
||||||
|
(const struct irq_domain_ops *ops)
|
||||||
|
{
|
||||||
|
gic_routable_irq_domain_ops = ops;
|
||||||
|
}
|
||||||
#endif /* __ASSEMBLY */
|
#endif /* __ASSEMBLY */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
include/linux/irqchip/irq-crossbar.h
Normal file
11
include/linux/irqchip/irq-crossbar.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* drivers/irqchip/irq-crossbar.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int irqcrossbar_init(void);
|
Loading…
Reference in New Issue
Block a user