Thread (36 messages) flat view 36 messages, 8 authors, 2012-01-14
STALE5345d

Revision v1 of 4 in this series.

Revisions (4)
  1. v1 current
  2. v2 [diff vs current]
  3. v3 [diff vs current]
  4. v4 [diff vs current]

[PATCH 04/15] ARM: smp_twd: add device tree support

From: Marc Zyngier <hidden>
Date: 2012-01-11 13:08:43
Subsystem: arm port, open firmware and flattened device tree bindings, the rest · Maintainers: Russell King, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Linus Torvalds

Add bindings to support DT discovery of the ARM Timer Watchdog
(aka TWD). Only the timer side is converted by this patch.

Cc: Rob Herring <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
 Documentation/devicetree/bindings/arm/twd.txt |   29 +++++++++++
 arch/arm/include/asm/smp_twd.h                |    1 +
 arch/arm/kernel/smp_twd.c                     |   68 ++++++++++++++++++++-----
 3 files changed, 85 insertions(+), 13 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/twd.txt
diff --git a/Documentation/devicetree/bindings/arm/twd.txt b/Documentation/devicetree/bindings/arm/twd.txt
new file mode 100644
index 0000000..a9d5587
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/twd.txt
@@ -0,0 +1,29 @@
+* ARM Timer Watchdog
+
+ARM 11MP, Cortex-A5 and Cortex-A9 are often associated with a per-core
+Timer-Watchdog (aka TWD), which provides both a per-cpu local timer
+and watchdog.
+
+The TWD is usually attached to a GIC to deliver its two per-processor
+interrupts.
+
+Main node required properties:
+
+- compatible : Should be one of:
+	"arm,cortex-a9-twd"
+	"arm,cortex-a5-twd"
+	"arm,arm11mp-twd"
+	"arm,smp-twd"
+
+- interrupts : Two interrupts to each core, the first one for the
+  timer, the second one for the watchdog.
+
+- reg : Specify the base address and the size of the TWD.
+
+Example:
+
+	twd at 2c000600 {
+		compatible = "arm,arm11mp-twd", "arm,smp-twd";
+		reg = <0x2c000600 0x100>;
+		interrupts = <1 13 0xf01 1 14 0xf01>;
+	};
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index 9b6ff85..e8998c9 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -31,5 +31,6 @@ struct twd_local_timer {
 };
 
 int twd_local_timer_register(struct twd_local_timer *);
+int twd_local_timer_of_register(void);
 
 #endif
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index be245c7..53ddef8 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -20,6 +20,8 @@
 #include <linux/clockchips.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 #include <asm/smp_twd.h>
 #include <asm/localtimer.h>
@@ -282,37 +284,77 @@ static struct local_timer_ops twd_lt_ops = {
 	.stop	= twd_timer_stop,
 };
 
-int __init twd_local_timer_register(struct twd_local_timer *tlt)
+static int __init twd_local_timer_common_register(void)
 {
 	int err;
 
-	if (twd_base || twd_evt)
-		return -EBUSY;
-
-	twd_ppi	= tlt->res[1].start;
-
 	twd_evt = alloc_percpu(struct clock_event_device *);
-	twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
-	if (!twd_base || !twd_evt) {
+	if (!twd_evt) {
 		err = -ENOMEM;
-		goto out;
+		goto out_free;
 	}
 
 	err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
 	if (err) {
 		pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
-		goto out;
+		goto out_free;
 	}
 
 	err = local_timer_register(&twd_lt_ops);
 	if (err)
-		goto out;
+		goto out_irq;
 
 	return 0;
 
-out:
+out_irq:
+	free_percpu_irq(twd_ppi, twd_evt);
+out_free:
 	iounmap(twd_base);
+	twd_base = NULL;
 	free_percpu(twd_evt);
-	twd_base = twd_evt = NULL;
+
 	return err;
 }
+
+int __init twd_local_timer_register(struct twd_local_timer *tlt)
+{
+	if (twd_base || twd_evt)
+		return -EBUSY;
+
+	twd_ppi	= tlt->res[1].start;
+
+	twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
+	if (!twd_base)
+		return -ENOMEM;
+
+	return twd_local_timer_common_register();
+}
+
+#ifdef CONFIG_OF
+const static struct of_device_id twd_of_match[] __initconst = {
+	{ .compatible = "arm,smp-twd", 		},
+	{ .compatible = "arm,cortex-a9-twd",	},
+	{ .compatible = "arm,cortex-a5-twd",	},
+	{ .compatible = "arm,arm11mp-twd",	},
+	{ },
+};
+
+int __init twd_local_timer_of_register(void)
+{
+	struct device_node *np;
+
+	np = of_find_matching_node(NULL, twd_of_match);
+	if (!np)
+		return -ENODEV;
+
+	twd_ppi = irq_of_parse_and_map(np, 0);
+	if (!twd_ppi)
+		return -EINVAL;
+
+	twd_base = of_iomap(np, 0);
+	if (!twd_base)
+		return -ENOMEM;
+
+	return twd_local_timer_common_register();
+}
+#endif
-- 
1.7.7.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help