Thread (23 messages) flat view 23 messages, 5 authors, 2012-01-27
STALE5310d REVIEWED: 1 (0M)

Revision v4 of 4 in this series; 1 review trailer.

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

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

From: Marc Zyngier <hidden>
Date: 2012-01-20 12:03:51
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.

Acked-by: Rob Herring <redacted>
Signed-off-by: Marc Zyngier <redacted>
---
 Documentation/devicetree/bindings/arm/twd.txt |   48 +++++++++++++++
 arch/arm/include/asm/smp_twd.h                |    8 +++
 arch/arm/kernel/smp_twd.c                     |   77 ++++++++++++++++++++----
 3 files changed, 120 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..75b8610
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/twd.txt
@@ -0,0 +1,48 @@
+* 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.
+
+** Timer node required properties:
+
+- compatible : Should be one of:
+	"arm,cortex-a9-twd-timer"
+	"arm,cortex-a5-twd-timer"
+	"arm,arm11mp-twd-timer"
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the TWD timer
+	register window.
+
+Example:
+
+	twd-timer at 2c000600 {
+		compatible = "arm,arm11mp-twd-timer"";
+		reg = <0x2c000600 0x20>;
+		interrupts = <1 13 0xf01>;
+	};
+
+** Watchdog node properties:
+
+- compatible : Should be one of:
+	"arm,cortex-a9-twd-wdt"
+	"arm,cortex-a5-twd-wdt"
+	"arm,arm11mp-twd-wdt"
+
+- interrupts : One interrupt to each core
+
+- reg : Specify the base address and the size of the TWD watchdog
+	register window.
+
+Example:
+
+	twd-watchdog at 2c000620 {
+		compatible = "arm,arm11mp-twd-wdt";
+		reg = <0x2c000620 0x20>;
+		interrupts = <1 14 0xf01>;
+	};
diff --git a/arch/arm/include/asm/smp_twd.h b/arch/arm/include/asm/smp_twd.h
index 16c89b7..8047e6e 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -40,4 +40,12 @@ struct twd_local_timer name __initdata = {	\
 
 int twd_local_timer_register(struct twd_local_timer *);
 
+#ifdef CONFIG_HAVE_ARM_TWD
+void twd_local_timer_of_register(void);
+#else
+static inline void twd_local_timer_of_register(void)
+{
+}
+#endif
+
 #endif
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index f105e91..d2dce64 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,86 @@ static struct local_timer_ops twd_lt_ops __cpuinitdata = {
 	.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,cortex-a9-twd-timer",	},
+	{ .compatible = "arm,cortex-a5-twd-timer",	},
+	{ .compatible = "arm,arm11mp-twd-timer",	},
+	{ },
+};
+
+void __init twd_local_timer_of_register(void)
+{
+	struct device_node *np;
+	int err;
+
+	np = of_find_matching_node(NULL, twd_of_match);
+	if (!np) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	twd_ppi = irq_of_parse_and_map(np, 0);
+	if (!twd_ppi) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	twd_base = of_iomap(np, 0);
+	if (!twd_base) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = twd_local_timer_common_register();
+
+out:
+	WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
+}
+#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