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

Marc Zyngier marc.zyngier at arm.com
Thu Dec 22 12:27:32 EST 2011


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 <rob.herring at calxeda.com>
Signed-off-by: Marc Zyngier <marc.zyngier at arm.com>
---
 Documentation/devicetree/bindings/arm/twd.txt |   29 +++++++++++
 arch/arm/include/asm/smp_twd.h                |    7 +++
 arch/arm/kernel/smp_twd.c                     |   67 +++++++++++++++++++-----
 3 files changed, 89 insertions(+), 14 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 934f1bc..09c3b71 100644
--- a/arch/arm/include/asm/smp_twd.h
+++ b/arch/arm/include/asm/smp_twd.h
@@ -20,6 +20,7 @@
 
 struct clock_event_device;
 struct resource;
+struct of_device_id;
 
 extern void __iomem *twd_base;
 
@@ -27,11 +28,17 @@ void twd_timer_setup(struct clock_event_device *);
 void twd_timer_stop(struct clock_event_device *);
 #ifdef CONFIG_HAVE_ARM_TWD
 int twd_timer_register(struct resource *res, int res_nr);
+int twd_timer_of_init(const struct of_device_id *twd_of_match);
 #else
 static inline int twd_timer_register(struct resource *res, int res_nr)
 {
 	return 0;
 }
+
+static inline int twd_timer_of_init(const struct of_device_id *twd_of_match)
+{
+	return 0;
+}
 #endif
 
 #endif
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index dedbdb4..98a6a59 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -18,6 +18,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_plat.h>
 #include <asm/smp_twd.h>
@@ -232,13 +234,40 @@ static struct notifier_block __cpuinitdata twd_cpu_nb = {
 	.notifier_call = twd_cpu_notify,
 };
 
-int __init twd_timer_register(struct resource *res, int res_nr)
+static int __init twd_timer_common_init(void)
 {
 	struct clock_event_device *clk;
+	int err;
 
-	if (!is_smp())
-		return -ENODEV;
+	if (!is_smp()) {
+		err = -ENODEV;
+		goto out_free;
+	}
+
+	twd_clock_event	= alloc_percpu(struct clock_event_device);
+	if (!twd_clock_event) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
+	/* Immediately configure the timer on the boot CPU */
+	clk = per_cpu_ptr(twd_clock_event, smp_processor_id());
+	twd_setup(clk);
+
+	register_cpu_notifier(&twd_cpu_nb);
+
+	return 0;
 
+out_free:
+	iounmap(twd_base);
+	twd_base = NULL;
+	free_percpu(twd_clock_event);
+
+	return err;
+}
+
+int __init twd_timer_register(struct resource *res, int res_nr)
+{
 	if (res_nr != 2 || res[1].start < 0)
 		return -EINVAL;
 
@@ -247,20 +276,30 @@ int __init twd_timer_register(struct resource *res, int res_nr)
 
 	twd_ppi		= res[1].start;
 	twd_base	= ioremap(res[0].start, resource_size(&res[0]));
-	twd_clock_event	= alloc_percpu(struct clock_event_device);
-	if (!twd_base || !twd_clock_event) {
-		iounmap(twd_base);
-		twd_base = NULL;
-		free_percpu(twd_clock_event);
+	if (!twd_base)
 		return -ENOMEM;
-	}
 
-	/* Immediately configure the timer on the boot CPU */
-	clk = per_cpu_ptr(twd_clock_event, smp_processor_id());
-	twd_setup(clk);
+	return twd_timer_common_init();
+}
 
-	register_cpu_notifier(&twd_cpu_nb);
+#ifdef CONFIG_OF
+int __init twd_timer_of_init(const struct of_device_id *twd_of_match)
+{
+	struct device_node *np;
 
-	return 0;
+	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_timer_common_init();
 }
 #endif
+#endif
-- 
1.7.7.1





More information about the linux-arm-kernel mailing list