* [PATCH v5 0/2] ARM: Exynos: Add irq_domain and device tree support for combiner
@ 2012-03-24 9:33 Thomas Abraham
2012-03-24 9:33 ` [PATCH v5 1/2] ARM: Exynos: Add irq_domain support for interrupt combiner Thomas Abraham
2012-03-24 9:33 ` [PATCH v5 2/2] ARM: Exynos: Add device tree " Thomas Abraham
0 siblings, 2 replies; 3+ messages in thread
From: Thomas Abraham @ 2012-03-24 9:33 UTC (permalink / raw)
To: linux-samsung-soc
Cc: devicetree-discuss, rob.herring, grant.likely, kgene.kim,
linux-arm-kernel, patches
Changes since v4:
- In patch 2/2, removed the #ifdef CONFIF_OF around irq_of_parse_and_map() as
suggested by Grant Likely. Hence this patch series depends on the patch
with subject "of/irq: add empty irq_of_parse_and_map() for non-dt builds".
- Rebased to the latest kgene/for-next branch which now includes support for
Exynos5. Since this patchset modifies portions of code that are common for
both Exynos4 and Exynos5, there are minor modifications in this patch series
to accommodate Exynos5 dt support as well.
- v4 of this patchset was acked by Grant Likely and Rob Herring. This patch
series (v5) has minor modifications over v4 to include Exynos5 support. Since
those modifications are minor (not related to irq_domain or dt functionality),
I am retaining the Ack from Grant and Rob for this series.
Changes since v3:
- In dt case, the use of fixed gic linux irq number to map the combiner
interrupt output is removed. This is replaced with the interrupt number
obtained from the gic irq domain. (Thanks to Rob Herring and Grant
Likely for this suggestion).
- Split the patch into two parts - irq_domain and device tree support
addition.
Changes since v2:
- Rebased to Grant's irqdomain/next branch.
Changes since v1:
- Includes all changes suggested by Rob Herring.
- Tested with SPARSE_IRQ enabled.
This patchset adds irq_domain and device tree support for the Exynos Interrupt
Combiner controller.
The first patch adds a common irq domain for the interrupts managed by the
interrupt combiners. All the instances of irq combiner reference the common irq
domain for translating hardware interrupts to linux irq number.
The second patch adds a interrupt specifier translator to support device tree
based instantiation. It can translate interrupt specifiers for device nodes
which use combiner as their interrupt parent.
This patchset is based on
http://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git [for-next]
with all patches merged from
http://git.secretlab.ca/git/linux-2.6.git [irqdomain/next]
Thomas Abraham (2):
ARM: Exynos: Add irq_domain support for interrupt combiner
ARM: Exynos: Add device tree support for interrupt combiner
.../bindings/arm/samsung/interrupt-combiner.txt | 52 ++++++++
arch/arm/mach-exynos/common.c | 138 ++++++++++++++-----
2 files changed, 153 insertions(+), 37 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v5 1/2] ARM: Exynos: Add irq_domain support for interrupt combiner
2012-03-24 9:33 [PATCH v5 0/2] ARM: Exynos: Add irq_domain and device tree support for combiner Thomas Abraham
@ 2012-03-24 9:33 ` Thomas Abraham
2012-03-24 9:33 ` [PATCH v5 2/2] ARM: Exynos: Add device tree " Thomas Abraham
1 sibling, 0 replies; 3+ messages in thread
From: Thomas Abraham @ 2012-03-24 9:33 UTC (permalink / raw)
To: linux-samsung-soc
Cc: devicetree-discuss, rob.herring, grant.likely, kgene.kim,
linux-arm-kernel, patches
Add irq_domain support for hardware interrupts of the interrupt combiner.
The hardware interrupts of all the instances of the combiner are grouped
in a single irq_domain.
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Rob Herring <rob.herring@calxeda.com>
---
arch/arm/mach-exynos/common.c | 87 +++++++++++++++++++++++-----------------
1 files changed, 50 insertions(+), 37 deletions(-)
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 85ed8b5..7518945 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -19,6 +19,8 @@
#include <linux/serial_core.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/export.h>
+#include <linux/irqdomain.h>
#include <asm/proc-fns.h>
#include <asm/exception.h>
@@ -394,6 +396,7 @@ struct combiner_chip_data {
void __iomem *base;
};
+static struct irq_domain *combiner_irq_domain;
static struct combiner_chip_data combiner_data[MAX_COMBINER_NR];
static inline void __iomem *combiner_base(struct irq_data *data)
@@ -406,14 +409,14 @@ static inline void __iomem *combiner_base(struct irq_data *data)
static void combiner_mask_irq(struct irq_data *data)
{
- u32 mask = 1 << (data->irq % 32);
+ u32 mask = 1 << (data->hwirq % 32);
__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_CLEAR);
}
static void combiner_unmask_irq(struct irq_data *data)
{
- u32 mask = 1 << (data->irq % 32);
+ u32 mask = 1 << (data->hwirq % 32);
__raw_writel(mask, combiner_base(data) + COMBINER_ENABLE_SET);
}
@@ -469,36 +472,59 @@ static void __init combiner_cascade_irq(unsigned int combiner_nr, unsigned int i
irq_set_chained_handler(irq, combiner_handle_cascade_irq);
}
-static void __init combiner_init(unsigned int combiner_nr, void __iomem *base,
- unsigned int irq_start)
+static void __init combiner_init_one(unsigned int combiner_nr,
+ void __iomem *base)
{
- unsigned int i;
- unsigned int max_nr;
-
- if (soc_is_exynos5250())
- max_nr = EXYNOS5_MAX_COMBINER_NR;
- else
- max_nr = EXYNOS4_MAX_COMBINER_NR;
-
- if (combiner_nr >= max_nr)
- BUG();
-
combiner_data[combiner_nr].base = base;
- combiner_data[combiner_nr].irq_offset = irq_start;
+ combiner_data[combiner_nr].irq_offset = irq_find_mapping(
+ combiner_irq_domain, combiner_nr * MAX_IRQ_IN_COMBINER);
combiner_data[combiner_nr].irq_mask = 0xff << ((combiner_nr % 4) << 3);
/* Disable all interrupts */
__raw_writel(combiner_data[combiner_nr].irq_mask,
base + COMBINER_ENABLE_CLEAR);
+}
+
+static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ irq_set_chip_and_handler(irq, &combiner_chip, handle_level_irq);
+ irq_set_chip_data(irq, &combiner_data[hw >> 3]);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ return 0;
+}
+
+static struct irq_domain_ops combiner_irq_domain_ops = {
+ .map = combiner_irq_domain_map,
+};
- /* Setup the Linux IRQ subsystem */
+void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
+{
+ int i, irq_base;
+ unsigned int max_nr, nr_irq;
+
+ max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
+ EXYNOS4_MAX_COMBINER_NR;
+ nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
+
+ irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
+ if (IS_ERR_VALUE(irq_base)) {
+ irq_base = COMBINER_IRQ(0, 0);
+ pr_warning("%s: irq desc alloc failed. Continuing with %d as "
+ "linux irq base\n", __func__, irq_base);
+ }
+
+ combiner_irq_domain = irq_domain_add_legacy(np, nr_irq, irq_base, 0,
+ &combiner_irq_domain_ops, &combiner_data);
+ if (WARN_ON(!combiner_irq_domain)) {
+ pr_warning("%s: irq domain init failed\n", __func__);
+ return;
+ }
- for (i = irq_start; i < combiner_data[combiner_nr].irq_offset
- + MAX_IRQ_IN_COMBINER; i++) {
- irq_set_chip_and_handler(i, &combiner_chip, handle_level_irq);
- irq_set_chip_data(i, &combiner_data[combiner_nr]);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ for (i = 0; i < max_nr; i++) {
+ combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
+ combiner_cascade_irq(i, IRQ_SPI(i));
}
}
@@ -511,7 +537,6 @@ static const struct of_device_id exynos4_dt_irq_match[] = {
void __init exynos4_init_irq(void)
{
- int irq;
unsigned int gic_bank_offset;
gic_bank_offset = soc_is_exynos4412() ? 0x4000 : 0x8000;
@@ -523,12 +548,7 @@ void __init exynos4_init_irq(void)
of_irq_init(exynos4_dt_irq_match);
#endif
- for (irq = 0; irq < EXYNOS4_MAX_COMBINER_NR; irq++) {
-
- combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
- COMBINER_IRQ(irq, 0));
- combiner_cascade_irq(irq, IRQ_SPI(irq));
- }
+ combiner_init(S5P_VA_COMBINER_BASE, NULL);
/*
* The parameters of s5p_init_irq() are for VIC init.
@@ -540,15 +560,8 @@ void __init exynos4_init_irq(void)
void __init exynos5_init_irq(void)
{
- int irq;
-
gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
-
- for (irq = 0; irq < EXYNOS5_MAX_COMBINER_NR; irq++) {
- combiner_init(irq, (void __iomem *)S5P_VA_COMBINER(irq),
- COMBINER_IRQ(irq, 0));
- combiner_cascade_irq(irq, IRQ_SPI(irq));
- }
+ combiner_init(S5P_VA_COMBINER_BASE, NULL);
/*
* The parameters of s5p_init_irq() are for VIC init.
--
1.6.6.rc2
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v5 2/2] ARM: Exynos: Add device tree support for interrupt combiner
2012-03-24 9:33 [PATCH v5 0/2] ARM: Exynos: Add irq_domain and device tree support for combiner Thomas Abraham
2012-03-24 9:33 ` [PATCH v5 1/2] ARM: Exynos: Add irq_domain support for interrupt combiner Thomas Abraham
@ 2012-03-24 9:33 ` Thomas Abraham
1 sibling, 0 replies; 3+ messages in thread
From: Thomas Abraham @ 2012-03-24 9:33 UTC (permalink / raw)
To: linux-samsung-soc
Cc: devicetree-discuss, rob.herring, grant.likely, kgene.kim,
linux-arm-kernel, patches
Add device tree based instantiation of the interrupt combiner controller.
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
---
.../bindings/arm/samsung/interrupt-combiner.txt | 52 +++++++++++++++++
arch/arm/mach-exynos/common.c | 61 ++++++++++++++++++--
2 files changed, 108 insertions(+), 5 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
diff --git a/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
new file mode 100644
index 0000000..f2f2171
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/interrupt-combiner.txt
@@ -0,0 +1,52 @@
+* Samsung Exynos Interrupt Combiner Controller
+
+Samsung's Exynos architecture includes a interrupt combiner controller which
+can combine interrupt sources as a group and provide a single interrupt request
+for the group. The interrupt request from each group are connected to a parent
+interrupt controller, such as GIC in case of Exynos4210.
+
+The interrupt combiner controller consists of multiple combiners. Upto eight
+interrupt sources can be connected to a combiner. The combiner outputs one
+combined interrupt for its eight interrupt sources. The combined interrupt
+is usually connected to a parent interrupt controller.
+
+A single node in the device tree is used to describe the interrupt combiner
+controller module (which includes multiple combiners). A combiner in the
+interrupt controller module shares config/control registers with other
+combiners. For example, a 32-bit interrupt enable/disable config register
+can accommodate upto 4 interrupt combiners (with each combiner supporting
+upto 8 interrupt sources).
+
+Required properties:
+- compatible: should be "samsung,exynos4210-combiner".
+- interrupt-controller: Identifies the node as an interrupt controller.
+- #interrupt-cells: should be <2>. The meaning of the cells are
+ * First Cell: Combiner Group Number.
+ * Second Cell: Interrupt number within the group.
+- reg: Base address and size of interrupt combiner registers.
+- interrupts: The list of interrupts generated by the combiners which are then
+ connected to a parent interrupt controller. The format of the interrupt
+ specifier depends in the interrupt parent controller.
+
+Optional properties:
+- samsung,combiner-nr: The number of interrupt combiners supported. If this
+ property is not specified, the default number of combiners is assumed
+ to be 16.
+- interrupt-parent: pHandle of the parent interrupt controller, if not
+ inherited from the parent node.
+
+
+Example:
+
+ The following is a an example from the Exynos4210 SoC dtsi file.
+
+ combiner:interrupt-controller@10440000 {
+ compatible = "samsung,exynos4210-combiner";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x10440000 0x1000>;
+ interrupts = <0 0 0>, <0 1 0>, <0 2 0>, <0 3 0>,
+ <0 4 0>, <0 5 0>, <0 6 0>, <0 7 0>,
+ <0 8 0>, <0 9 0>, <0 10 0>, <0 11 0>,
+ <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>;
+ };
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 7518945..36b5837 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -21,6 +21,7 @@
#include <linux/of_irq.h>
#include <linux/export.h>
#include <linux/irqdomain.h>
+#include <linux/of_address.h>
#include <asm/proc-fns.h>
#include <asm/exception.h>
@@ -486,6 +487,30 @@ static void __init combiner_init_one(unsigned int combiner_nr,
base + COMBINER_ENABLE_CLEAR);
}
+#ifdef CONFIG_OF
+static int combiner_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)
+{
+ if (d->of_node != controller)
+ return -EINVAL;
+ if (intsize < 2)
+ return -EINVAL;
+ *out_hwirq = intspec[0] * MAX_IRQ_IN_COMBINER + intspec[1];
+ *out_type = 0;
+ return 0;
+}
+#else
+static int combiner_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)
+{
+ return -EINVAL;
+}
+#endif
+
static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
@@ -496,16 +521,26 @@ static int combiner_irq_domain_map(struct irq_domain *d, unsigned int irq,
}
static struct irq_domain_ops combiner_irq_domain_ops = {
+ .xlate = combiner_irq_domain_xlate,
.map = combiner_irq_domain_map,
};
void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
{
- int i, irq_base;
+ int i, irq, irq_base;
unsigned int max_nr, nr_irq;
- max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
+ if (np) {
+ if (of_property_read_u32(np, "samsung,combiner-nr", &max_nr)) {
+ pr_warning("%s: number of combiners not specified, "
+ "setting default as %d.\n",
+ __func__, EXYNOS4_MAX_COMBINER_NR);
+ max_nr = EXYNOS4_MAX_COMBINER_NR;
+ }
+ } else {
+ max_nr = soc_is_exynos5250() ? EXYNOS5_MAX_COMBINER_NR :
EXYNOS4_MAX_COMBINER_NR;
+ }
nr_irq = max_nr * MAX_IRQ_IN_COMBINER;
irq_base = irq_alloc_descs(COMBINER_IRQ(0, 0), 1, nr_irq, 0);
@@ -524,13 +559,29 @@ void __init combiner_init(void __iomem *combiner_base, struct device_node *np)
for (i = 0; i < max_nr; i++) {
combiner_init_one(i, combiner_base + (i >> 2) * 0x10);
- combiner_cascade_irq(i, IRQ_SPI(i));
+ irq = np ? irq_of_parse_and_map(np, i) : IRQ_SPI(i);
+ combiner_cascade_irq(i, irq);
}
}
#ifdef CONFIG_OF
+void __init combiner_of_init(struct device_node *np, struct device_node *parent)
+{
+ void __iomem *combiner_base;
+
+ combiner_base = of_iomap(np, 0);
+ if (!combiner_base) {
+ pr_err("%s: failed to map combiner registers\n", __func__);
+ return;
+ }
+
+ combiner_init(combiner_base, np);
+}
+
static const struct of_device_id exynos4_dt_irq_match[] = {
{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
+ { .compatible = "samsung,exynos4210-combiner",
+ .data = combiner_of_init, },
{},
};
#endif
@@ -548,7 +599,8 @@ void __init exynos4_init_irq(void)
of_irq_init(exynos4_dt_irq_match);
#endif
- combiner_init(S5P_VA_COMBINER_BASE, NULL);
+ if (!of_have_populated_dt())
+ combiner_init(S5P_VA_COMBINER_BASE, NULL);
/*
* The parameters of s5p_init_irq() are for VIC init.
@@ -561,7 +613,6 @@ void __init exynos4_init_irq(void)
void __init exynos5_init_irq(void)
{
gic_init(0, IRQ_PPI(0), S5P_VA_GIC_DIST, S5P_VA_GIC_CPU);
- combiner_init(S5P_VA_COMBINER_BASE, NULL);
/*
* The parameters of s5p_init_irq() are for VIC init.
--
1.6.6.rc2
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2012-03-24 9:33 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-03-24 9:33 [PATCH v5 0/2] ARM: Exynos: Add irq_domain and device tree support for combiner Thomas Abraham
2012-03-24 9:33 ` [PATCH v5 1/2] ARM: Exynos: Add irq_domain support for interrupt combiner Thomas Abraham
2012-03-24 9:33 ` [PATCH v5 2/2] ARM: Exynos: Add device tree " Thomas Abraham
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).